Thank for watch
解决比特难题,整数操作问题和浮点问题 比特难题:
名字描述评分bitAnd(x,y)使用|和~完成x&y1getByte(x,n)从x得到第n字节的数2logicalShift(x,n)使用算数右移完成逻辑右移3bitCount(x)x中有多少个14bang(x)不用!实现!操作符4整数操作问题
名字描述评分tmin()返回最小补码1fitsBits(x,n)x能用n bits表示吗2divpwr2(x,n)计算 x/(2^n)2negate(x)不用负号完成取反2isPosition(x)x大于0吗3isLessOrEqual(x,y)x小于等于y吗3ilog2(x)计算floor(log2(x))4浮点问题
名字描述评分float_neg(uf)取反2float_i2f(x)计算(float)x4float_twice(uf)计算x*2.04完成实验你只需要修改bits.c.配套有btest,dlc和fshow配件。 在本实验中: 不能使用循环,分支语句。只允许使用顺序语句。 只能使用 ! ˜ & ˆ | + << >>(甚至更少) 只能使用小于256的常数。 只能使用int或unsigned,不能使用float,不能类型转换 在每个函数的注释有更清楚的任务要求
这个工具检查bits.c里函数的正确性。(每次修改完bits.c都要重新make) ./btest 检查你的所有答案是否正确 ./btest -f bitAnd 检查bitAnd是否正确。
./dlc bits.c 检查你使用了非法操作符,或过多的操作符,或循环,分支语句 ./dlc -e bits.c 检查你每个函数使用的操作符数量
./driver.pl 算出你的最后得分
要求:使用**~**和 **|**完成 x&y 例:bitAnd(6,5)=4 允许操作 ~ | 操作符限定:8 分值:1
摩根定律的运用 ``` int bitAnd(int x, int y) { return ~(~x | ~y); } ``` ### getByte 要求:从x中提取第n字节 例:bitAnd(0x12345678,1)=0x56 允许操作 **!** **~** **^** **|** **+** **<<** **>>** 操作符限定:6 分值:2 ``` int getByte(int x, int n) { x=x>>(n<<3); return x&0xff; ``` } ### logicalShift 要求:用算数右移实现逻辑右移 例:logicalShift(0x87654321,4)=0x08765432 允许操作 **!** **~** **^** **&** **^** **+** **<<** **>>** 操作符限定:20 分值:3 ``` int logicalShift(int x, int n) { int xsra = x >> n; int mask = ~0<<(32+~n)<<1; mask = ~mask; return xsra&mask; } ``` ### bitCount 要求:计算x里有多少个1 例:bitAnd(5)=2 bitCount(7)=3 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:40 分值:4 首先将32位数分为8组,对于每四位数,通过三次移位运算统计每组数中1的个数,然后将前16位与后16位相加,将1的个数浓缩在16位中,再以同样的方法将1的个数整理到4位中,得到最后结果。· [类似思路](https://blog.csdn.net/weixin_41256413/article/details/79937907) ``` int bitCount(int x) { int i = 0x11 | (0x11 << 8); i = i + (i << 16); int sum = 0; sum += x & i; sum += (x >> 1) & i; sum += (x >> 2) & i; sum += (x >> 3) & i; i = 0xff + (0xff << 8); sum = (sum >> 16) + (sum & i); i = 0x0f + (0x0f << 8); sum = ((sum >> 4) & i) + (sum & i); i = 0xff; sum = (sum & i) + (sum>>8); return sum;}
<br> <br> <br> ### bang 要求:不用!实现!x 例:bang(3)=0,bang(0)=1 允许操作 **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:12 分值:4<br> <br> 如果不懂,可以看下面链接,有讲的很详细 [思路](https://blog.csdn.net/weixin_41256413/article/details/79937907)int bang(int x) { x = (x>>1)|x; x = (x>>2)|x; x = (x>>4)|x; x = (x>>8)|x; x = (x>>16)|x; return ~(x & 1)+2; }
<br> <br> <br> ### tmin 要求:返回最小补码 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:4 分值:1<br> <br>int tmin(void) { return 0x80<<24; }
<br> <br> <br> ### fitsBits 要求:n bit能表示x吗 例:bitAnd(5,3)=0 bitCount(-4,3)=1 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:15 分值:2<br> <br> 这题其实考补码符号扩展,将x右移(n+~0)位,即得到了符号位<br> 负数:0xffffffff正数0x0。int fitsBits(int x, int n) { x = x>>(n+~0); return !x | !(x+1); }
<br> <br> <br> ### divpwr2 要求:计算x/(2^n) 0<=n<=30,向0舍入 例:divpwr2(15,1)=7 divpwr2(-33,4)=-2 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:15 分值:2<br> <br> 这题,如果x小于0,要加上偏置。int divpwr2(int x, int n) { int sign = (x>>31); x = x + (sign & ((1<<n)+~0) ); return x >> n; }
<br> <br> <br> ### negata 要求:取反 例:negata(1)=-1 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:5 分值:2<br> <br> 相信国产的书都是这么教补码的(道理在书上的web sides上。这里给出[原理网址](http://csapp.cs.cmu.edu/3e/waside/waside-tneg.pdf)所以不赘述了 int negate(int x) { return ~x + 1; } <br> <br> <br> ### isPositive 要求:x大于0吗 例:isPositive(-1)=0 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:8 分值:3<br> <br> 把情况分为正数,0,负数就好懂了int isPositive(int x) { return !(x>>31) & !!x; //or //retunrn !(x>>31); }
<br> <br> <br> ### isLessOrEqual 要求:y大于等于x吗 例:isLessOrEqual(4,5) = 1. 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:24 分值:3<br> <br> equal是符号相同。在这个情况下,如果x更大,~y+x是0.。如果y更大。~y+x是1 nequal是符号不同.int isLessOrEqual(int x, int y) { unsigned sign_x = x>>31; unsigned sign_y = y>>31; unsigned equal = !(sign_x ^ sign_y) & ((x+~y)>>31); unsigned nequal = sign_x & !sign_y; return equal | nequal; }
<br> <br> <br> ### ilog2 要求:计算floor(log2(x)) 例:ilog2(16) = 4 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:90 分值:4<br> <br> 这个问题可以转换为x最高位是几 前半段[思路](https://blog.csdn.net/weixin_41256413/article/details/79937907) 后半段确定最高位是第几位 bit_16确定前16位有没有。如果有。bit_16=16,且x右移16位, bit_8确定前8位有没有。如果有。bit_8=8,且x右移8位, bit_4确定前4位有没有。如果有。bit_4=4,且x右移4位, bit_2确定前2位有没有。如果有。bit_2=2,且x右移2位, bit_1确定前1位有没有。如果有。bit_1=1,且x右移1位, 最后相加,即可知道最高位是几int ilog2(int x){ x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; x = x^(x>>1); int bit_16,bit_8,bit_4,bit_2,bit_1; bit_16 = !(!(x>>16))<<4; x = x>>bit_16; bit_8 = !(!(x>>8))<<3; x = x>>bit_8; bit_4 = !(!(x>>4))<<2; x = x>>bit_4; bit_2 = !(!(x>>2))<<1; x = x>>bit_2; bit_1 = !(!(x>>1));
return bit_16+bit_8+bit_4+bit_2+bit_1;}
<br><br><br> ### float_neg 要求:取反,如果x是NaN,返回x 允许操作 循环,分支等等都能用,除了float类型和强制转换类型 操作符限定:10 分值:2<br> <br> 题目说了,注意NaN,那咱们就注意NaNunsigned float_neg(unsigned uf){ unsigned exp = uf>>23 &0xFF; unsigned frac = uf & 0x7FFFFF; if(exp==0xFF && frac!=0) return uf; unsigned mask = 1<<31; return uf ^ mask; }
<br> <br> <br> ### float_i2f 要求:返回(float)x 例:ilog2(16) = 4 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:30 分值:4<br> <br> 首先:要找到该int的最高位数,这样确定位移的大小 当左移时,自然不用考虑舍入的问题。 当右移时,要考虑最大舍入+偶数舍入,这是最需要思考的地方unsigned float_i2f(int x) { if(x==0) return 0; unsigned sign = !!(x>>31); if(x<0) x = ~x+1; unsigned exp =127; unsigned frac =x; //find the highest bit unsigned j; for (j = (sizeof(int) << 3) - 1; j >= 0; --j) { if ((frac >> j) & 1) break; } if(j<23){ frac <<=(23-j); exp += j; } else{ frac>>=(j-23); exp +=j; unsigned mask = (1 << (j - 23)) - 1; if ((x&mask) >(1 << (j - 24))) frac++; //需要舍入到大值 else if ((x&mask) == 1 << (j - 24) && (frac & 1)) frac++; //舍入到偶数 if (frac == (1 << 24)) exp++; //舍入到偶数超过(1<<24) - 1,指数需要再加1 } frac&=0x7FFFFF; return (sign<<31) | (exp<<23) | frac; }
<br> <br> <br> ### float_twice 要求:返回x*2.0,如果是NaN,返回x 允许操作 **!** **~** **&** **^** **|** **+** **<<** **>>** 操作符限定:30 分值:4<br> <br> 分情况讨论 f 非规格是 小数左移一位即时*2.0 f在最大非规格 用公式推出即可 f在规格数里。将exp+1即时*2 f在规格数里,exp已经到1111 1110.再乘2.0就变为了+∞ f位无穷大或者NaN,直接返回funsigned float_twice(unsigned uf) { unsigned sign = uf>>31; unsigned exp = uf>>23 & 0xFF; unsigned frac = uf & 0x7FFFFF;
if(exp==0 && frac< 0x7FFFFF) frac <<=1; else if(exp ==0 && frac==0x7FFFFF){ exp+=1; frac = 0x7FFFFE; } else if(exp==0xFE){ exp = 0xFF; frac=0; } else if(exp==0xFF) return uf; else exp+=1; return (sign<<31) | (exp<<23) | frac;}
