DataLab思路+答案

DataLab

在这里插入图片描述
可以总结很多,要回顾

bitXor
//1
/* 
 * bitXor - x^y using only ~ and & 
 *   Example: bitXor(4, 5) = 1
 *   Legal ops: ~ &
 *   Max ops: 14
 *   Rating: 1
 */
int bitXor(int x, int y) {
  return ~(x&y)&~(~x&~y);
}
tmin
/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4

 *   Rating: 1
 */
int tmin(void) {
  return 0x1<<31;
}
isTmax

题目:通过位运算计算是否是补码最大值

思考:

  1. tmax与一般数值的不同之处在于,再往上加就会溢出(5位bit为例),是否有什么特别的呢?
  2. tmax : 01111 + 1 得到 10000(第一个1权值为-16) (15变-16)
  3. ~tmax=10000
  4. 故~tmax=tmax+1
  5. 可验证-1(11111)也有此性质,其余无
  6. 以上结论也可由-tmin=~tmin+1=tmin性质推导出来
  7. 故解决办法:用异或判断~x和x+1是否相等,并且排除-1
//2
/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
 	 return  !( (x+1)^(~x) ) &  (!!(~x));
}

allOddBits
/* 
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   where bits are numbered from 0 (least significant) to 31 (most significant)
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
//  return !(~x&0xaaaaaaaa);不能用大常量
	int t=(0xaa<<24)+(0xaa<<16)+(0xaa<<8)+(0xaa);//自己构造0xaaaaaaaa
    return !(~x&t);
}

negate

题目:求 -x 值

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  return ~x+0x1;
}

isAsciiDigit

题目:计算输入值是否是数字 0-9 的 ASCII 值

思路:
1.若在其中,必定满足x -0x30>=0且x-0x3a<0
2.根据1.判断符号位即可

//3
/* 
 * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
 *   Example: isAsciiDigit(0x35) = 1.
 *            isAsciiDigit(0x3a) = 0.
 *            isAsciiDigit(0x05) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 3
 */
int isAsciiDigit(int x) {
	return !((x+(~0x30+1))>>31)&((x+(~0x3a+1))>>31);
}
conditional

题目:使用位级运算实现 C 语言中的 x?y:z 三目运算符

思考:

  1. 怎么区分0和非0数?
  2. !x 即可,得到0x01或者0x00
  3. 要变成0x0000000和0xffffffffff如何操作?
  4. 法1:!x-1 即 !x+(~1+1)
  5. 法2:!x<<31>>31
  6. 上面两种方法可以在0,1,全1,全0中变换,很实用
  7. 若想全0或全1,变成1,0,则+1即可,0xffffff溢出为0,0x00000变成1
/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
  //return (!x+(~1+1))&y|~(!x+(~1+1))&z;
  return (!x<<31>>31)&z | ~(!x<<31>>31)&y;
}

isLessOrEqual

使用位级运算符实现 <=

思路:

  1. y-x>=0判断符号位
  2. 若2者异号,相减会出现相加情况(相当于两个正数或者两个负数相加),可能出现溢出,不适合通过结果的符号位判断
  3. 故若二者异号,直接判断 x<0,返回1,x>0,返回0
/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
	
   int isSameSign= !( ((x^y)>>31) & 0x1 );//&0x1将不需要的位置0,以免影响结果
   int e= (( y+(~x+1) ) >> 31) & 0x1;
  return ( isSameSign & !e ) | ( !isSameSign & ( (x>>31)&0x1) );
}

若改成
  int e= (( x+(~y+1) ) >> 31) & 0x1;
  需要多一步判断x等于y的情况
logicalNeg

题目:使用位级运算求逻辑非 !

思路:

  1. 区别0和非0数值的特征是什么
  2. +0=-0 符号位相同,tmin=-tmin
  3. 其余+x 和 -x 符号位不同
  4. 故解决办法:通过或运算,判断符号位,不通过异或是因为tmin的存在,只有0和-0符号位 或 为0
  5. 判断该符号位,若为0返回1,若为1返回0(通过>>31+1实现)
//4
/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int logicalNeg(int x) {
  return  return (((~x+1)|x)>>31) +1 ;//>>31变成全0或全1,+1后,0变1,全1溢出为0,返回
}

howManyBits

题目:“一个数用补码表示最少需要几位?”

思考:

  1. 怎么确定补码表示该数的位数?关键点在于?
  2. 负数:第一个0的位置+1,取反变成找第一个1的位置
  3. 正数:第一个1的位置+1
  4. 前16位是否有1?若有,起码需要16位,故去掉后16位(右移16),若没有,不移位
  5. 考察前8位是否有1?
  6. …不断缩小范围,累加确定的位数
/* howManyBits - return the minimum number of bits required to represent x in
 *             two's complement
 *  Examples: howManyBits(12) = 5
 *            howManyBits(298) = 10
 *            howManyBits(-5) = 4
 *            howManyBits(0)  = 1
 *            howManyBits(-1) = 1
 *            howManyBits(0x80000000) = 32
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 90
 *  Rating: 4
 */
int howManyBits(int x) {
 int b16,b8,b4,b2,b1,b0;
	int sign=x>>31;
	x=sign&(~x) | (~sign)&x;//如果x为正则不变,否则按位取反(统一找最高位为1)
	b16=!!(x>>16)<<4;//判断前16位是否有1,并且同时计算了需要移位的位数
	x=x>>b16;//有1就移动16位,否则b16=0,不移动
	b8=!!(x>>8)<<3;
	x=x>>b8;
	b4=!!(x>>4)<<2;
	x=x>>b4;
	b2=!!(x>>2)<<1;
	x=x>>b2;
	b1=!!(x>>1);
	x=x>>b1;
	b0=x;
  return b16+b8+b4+b2+b1+b0+1;
}

floatScale2

题目:求 2 乘一个浮点数

思路:

  1. 若为非规格化数,exp全0,只能通过frac左移一位变成2倍(见下图)
  2. 若为规格化数,frac有隐藏位,无法移动,可通过exp+1来变成2倍
  3. 若为NaN,无穷,返回参数(变2倍之前)
  4. 变2倍后变成无穷,返回无穷
//float
/* 
 * floatScale2 - Return bit-level equivalent of expression 2*f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representation of
 *   single-precision floating point values.
 *   When argument is NaN, return argument
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned floatScale2(unsigned uf) {
//分别取符号位,尾数,指数
	int sign=uf&(1<<31);
	int frac=uf&0x007fffff;
	int exp=(uf>>23)&0xff;
	
	//非规格化数,指数全0,尾数无隐藏位,故可通过左移一位变为2倍,考察临界值(非规格化最大数),也成立,见下图绿色部分
	if(exp==0) return uf<<1|sign;
	
	//NaN,无穷大
	if(exp==255)  return uf;
	
	//规格化数,有隐藏位,故通过改变指数变成2倍
	exp++;
	if(exp==255) return 0x7f800000|sign;
	return exp<<23|frac|sign;
	 
}

在这里插入图片描述

floatFloat2Int

题目:将浮点数转换为整数

思路:

  1. 分别取出s,exp,frac
  2. 补充frac的隐藏位1,得到完整尾数m
  3. exp-bias得到指数e,根据指数e来移位
  4. e<0,小数点左移,一定为小数,舍入为0
  5. e>31,小数点右移,最高位溢出,返回给定溢出值tmin
  6. 小数点后有23位,根据e与23大小关系,正确移位
  7. 正确移位完成得到整数M,此为数值大小,再进行符号判断
  8. 若M最高位跟原S符号相同直接返回
  9. 若不同,且M最高位为1,则用现有位无法表示(需要额外一个位来表示符号)
  10. 若不同,且M最高位为0,则返回-M即(~M+1)
/* 
 * floatFloat2Int - Return bit-level equivalent of expression (int) f
 *   for floating point argument f.
 *   Argument is passed as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point value.
 *   Anything out of range (including NaN and infinity) should return
 *   0x80000000u.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
int floatFloat2Int(unsigned uf) {

    int tmin=0x1<<31;//溢出需返回的值
	int sign=uf>>31;//取符号
	int frac=uf&0x007fffff;//取尾数
	int e=((uf>>23)&0xff)-127;//取指数  exp-偏置( 2^7 -1)=127
 	int M = frac|(0x1<<23);//补充隐藏位1
 
	if(e<0) return 0; //如果指数小于0,相当于尾数小数点左移,必定为小数,舍入为0
	if(e>31) return tmin;//如果指数大于31,相当于尾数小数点右移31,溢出
	if(e>23) M=M<<(e-23);//如果指数>23,小数点左移e-23
	else M=M>>(23-e);	//否则右移23-e

	if(!( (M>>31) ^sign)) return M;//如果移动完成的尾数M符号位与sign相同,无需转换,直接返回M
	else if(M>>31) return tmin;//如果不同,且M为负数,则无法表示(需更多位),返回溢出
	else return ~M+1;	//如果不同,且M为正数,返回其相反数
}
floatPower2

思路:
求2.0x,即1*2.0x,转为浮点表示
s=0,e=x,frac=0
假设为规格化数:exp=e+bias=x-127,考察e范围,根据e判断返回值

梳理:浮点表示中,用exp来编码指数e,exp是无符号数,范围为1~+254(规格化范围),故指数e的范围为-126 ~+ 127,
若e<-126 ,exp<1,为非规格化数,且frac全0,故为0
若e>127,exp>254,全1,为非规格化数,且frac全0,s为0,故为+INF

见上图比较清晰

/* 
 * floatPower2 - Return bit-level equivalent of the expression 2.0^x
 *   (2.0 raised to the power x) for any 32-bit integer x.
 *
 *   The unsigned value that is returned should have the identical bit
 *   representation as the single-precision floating-point number 2.0^x.
 *   If the result is too small to be represented as a denorm, return
 *   0. If too large, return +INF.
 * 
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while 
 *   Max ops: 30 
 *   Rating: 4
 */
unsigned floatPower2(int x) {

	int inf=0x7f800000;
	if(x<-126) return 0;
	if(x>127) return inf;
	return (x+127)<<23;
}
  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值