试验获取请到官网 CSAPP

1.bitXor

  1. int bitXor(int x, int y) {
  2. return (~(x&y)) & (~((~x)&(~y)));
  3. }
  • 左边表达式筛选出 0,1 1,0 0,0 三种情况得到1,右边表达式排除 0,0 得到1,二者一起得到 0,1 1,0 即异或

    2.tmin

  1. int tmin(void) {
  2. return 1<<31;
  3. }
  • 很简单

    3.isTmax

  1. int isTmax(int x) {
  2. return !(((~(x+1))^x) | (!(~x)));
  3. }
  • 或运算 | 左边筛选出 0x7fffffff 和 0xffffffff 得到全0 , 右边对于 0x7fffffff 得到全0, 对于 0xffffffff 得到1 ,经过或运算之后只有目标Tmax 0x7fffffff 会得到0,取非之后返回

    4.AllOddBits

  1. int allOddBits(int x) {
  2. int allodd0 = (0x55<<24) + (0x55<<16) + (0x55<<8) +0x55;
  3. return !(~(allodd0 | x));
  4. }
  • 比较简单,用奇数位全0,偶数位全1去进行或运算即可

    5.negate

  1. int negate(int x) {
  2. return (~x) + 1;
  3. }
  • x + ~x + 1 = 0

    6.isAscciiDigit

  1. int isAsciiDigit(int x) {
  2. int a = (x>>3)^0x6;
  3. int b = x^0x38;
  4. int c = x^0x39;
  5. return !a | !b | !c;
  6. }
  • a 筛选出 0x30 至 0x37 ,若符合 a 的值为 0 ,b 筛选 0x38 , c 筛选 0x39

    7.conditional

  1. int conditional(int x, int y, int z) {
  2. int negative1 = ~1 + 1; //-1
  3. int control = !x + negative1; //x=0 ,c=0 ;x!=0 ,c=0xffffffff
  4. return (y&control) + (z&(~control));
  5. }
  • 想了好久,思路在代码里,关键点是 0-1=0xffffffff

    8.isLessOrEqual

  1. int isLessOrEqual(int x, int y) {
  2. int negativex = ~x+1;
  3. int a = !((!(x>>31))|(y>>31)); //x<0 且 y>=0
  4. int b = (( !((x>>31)^(y>>31)) ) & (!((y+negativex)>>31) | !(x^(1<<31))));
  5. // x,y异号 且 ( y-x>=0 或 x=0xffffffff )
  6. return a | b;
  7. }
  • 这道题就是用来说明 x<=y 不代表 x-y<=0 的,Tmin 和 Tmax 两个边界很要命 ,还有运算可能溢出。

    9.logicalNeg

  1. int logicalNeg(int x) {
  2. return ((x|(~x+1))>>31)+1;;
  3. }
  • 除了 0 和 Tmin 以外,所有数和其补码都是异号的,而 Tmin 的符号位为1,所以在和自己的补码逻辑或运算以后,只有 0 的符号位为 0 ,以此求解

    10.howManyBits

  1. int howManyBits(int x) {
  2. int shift1,shift2,shift4,shift8,shift16;
  3. int sum;
  4. int t=((!x)<<31)>>31;//x为0时,t(二进制)全为1,x不为0时,全为1
  5. int t2=((!~x)<<31)>>31;//当x为-1时,t2全为1,否则,全为0
  6. int op=x^((x>>31));//正数不变,负数取反
  7. shift16=(!!(op>>16))<<4;//如果高十六位全为0,则0左移4位,不全为0,则1左移4(表示op要右移2^4位)位
  8. op=op>>shift16;
  9. shift8=(!!(op>>8))<<3;
  10. op=op>>shift8;
  11. shift4=(!!(op>>4))<<2;
  12. op=op>>shift4;
  13. shift2=(!!(op>>2))<<1;
  14. op=op>>shift2;
  15. shift1=(!!(op>>1));
  16. op=op>>shift1;
  17. sum=2+shift16+shift8+shift4+shift2+shift1;
  18. return(t2&1)|((~t2)&((t&1)|((~t)&sum)));
  19. }
  • 略有点复杂,最后参考了这篇 ,这个二分法挺巧妙的

    11.floatScale2

  1. unsigned floatScale2(unsigned uf) {
  2. int e = (uf>>23) & 0xff;
  3. int rte = e+1;
  4. if(!e)//e=0
  5. return (uf&0xf0000000) + ((uf&0x7fffff)<<1);
  6. else if(!(e^0xff))
  7. return uf;
  8. else if(rte&(1<<8))
  9. return ((uf>>31)<<31) + (0xff<<23);
  10. else
  11. return (uf&(0x807fffff)) + (rte<<23);
  12. }
  • 规格化的浮点数乘2就是把阶码加一,非规格化和特殊值单独处理

    12.floatFloat2Int

  1. int floatFloat2Int(unsigned uf)
  2. {
  3. int e = (uf >> 23) & 0xff; //阶码
  4. int f = uf & 0x7fffff; //尾码
  5. int tag = uf & 0x80000000; //符号位
  6. if (e <= 126) //小于0
  7. return 0;
  8. else if (e > 157) //上溢
  9. return 0x80000000;
  10. else //范围内
  11. {
  12. int s = e - 127;
  13. f = f + 0x800000;
  14. if (s >= 23)
  15. {
  16. int r = f << (s - 23);
  17. if (tag)
  18. return -r;
  19. else
  20. return r;
  21. }
  22. else
  23. {
  24. int r = (f >> (23 - s));
  25. if (tag)
  26. return -r;
  27. else
  28. return r;
  29. }
  30. }
  31. }
  • 题目不难,就是逻辑有点复杂,还要注意c/c++中的舍入是断尾法

    13.floatPower2

  1. unsigned floatPower2(int x) {
  2. unsigned INF = 0xff << 23; // 阶码全1
  3. int e = 127 + x; // 得到阶码
  4. if (x < 0) // 阶数小于0直接返回0
  5. return 0;
  6. if (e >= 255) // 阶码>=255直接返回INF
  7. return INF;
  8. return e << 23;
  9. // 直接将阶码左移23位,尾数全0,规格化时尾数隐藏有1个1作为底数
  10. }
  • 不难

最后一题有个小插曲,就是最后一个题目测试时会提示死循环
CSAPP: datalab - 图1
但是逻辑是没有问题的,最后看了下测试文件的代码,在 btest.c 文件的开头限制了超时时间为10s,
CSAPP: datalab - 图2
将TIMEOUT_LIMIT修改为100,测试通过
CSAPP: datalab - 图3

最后是完整文件

完整文件

小结

慕名而来看了CSAPP,不得不说看了这本书写的真的很好,看完第二章我对浮点数的认知确实更清晰了,后续我做了其他lab之后,也会逐一发上来,欢迎大家关注。