• 深入理解计算机原理(csapp第三版)——datalab


    代码:https://gitee.com/iwehdio/csapp-lab

    1. bitXor

    bitXor - x^y using only ~ and &

    Example: bitXor(4, 5) = 1

    Legal ops: ~ &

    Max ops: 14

    Rating: 1

    • 异或,只能用~和&,操作数最大14个
    int bitXor(int x, int y) {
        int res = ~(~(x & ~y) & ~(~x & y));
        return res;
    }
    
    • 思路
      • 异或,就是不同时才为1,相同时为0。那么,使用非~就可以找出,x & y为1的位就是x为1但是y为0的位,x & y为1的位就是x为0但是y为1的位。
      • 找出异或为1的位后,需要做一个或运算,但是本题中不能用|。用~(a | b)==~a & ~b来代替。
    • 其他答案
    int bitXor(int x, int y) {
      return ~(~x&~y)&~(x&y);
    }
    
    • 这个利用的是,x&y为1的位是同时为0的,x&y为1的位是同时为1的,那么其按位非就是不同时为1且不同时为0的。

    2. tmin

    tmin - return minimum two's complement integer

    Legal ops: ! ~ & ^ | + << >>

    Max ops: 4

    Rating: 1

    • 2的补码的最小值
    int tmin(void) {
        int res = 1 << 31;
        return res;
    }
    
    • 只把符号位置为1就行了

    3. isTmax

    isTmax - returns 1 if x is the maximum, two's complement number, and 0 otherwise

    Legal ops: ! ~ & ^ | +

    Max ops: 10

    Rating: 1

    • 如果返回的是补码的最大值,就返回1
    int isTmax(int x) {
        int addOne = x + 1;
        int res = addOne ^ ~x;
        return !(res + !addOne);
    }
    
    • 一个数的相反数的表示和这个数加一一样,这种情况只存在于符号转变的从-1到0和从TMax到TMin之间。排除0的情况就是TMax了

    4. 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

    • 如果所有的奇数位都为1就返回1,位数是从零开始数的。
    int allOddBits(int x) {
        int mask = 0xAA;
        mask |= mask << 8;
        mask |= mask << 16;
        int res = (x & mask) ^ mask;
        return !res;
    }
    

    5. negate

    negate - return -x

    Example: negate(1) = -1.

    Legal ops: ! ~ & ^ | + << >>

    Max ops: 5

    Rating: 2

    • 返回负数
    int negate(int x) {
        int res = ~x + 1;
      return res;
    }
    
    • 相反数就是补码加一

    6. isAsciiDigit

    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

    • 返回数值在0x30和0x39之间的数
    int isAsciiDigit(int x) {
        int highBit = !((x >> 4) ^ 0x3);
        int bitOne = (x>>3) & 0x1;
        int bit23 = (x>>1) & 0x3;
        return highBit & (!bitOne | !bit23);
    }
    
    • 0x30 → 0011 0000 0x39 → 0011 1001
    • 在这个范围内的,首先第一位必须是0011
    • 其次第二位有两种情况,最高位为0时,总是符合(0000~0111);最高位为1时,必须有中间两位为0(1000,1001)
    • 其他答案
      • 可以使用两个数,一个数是加上比0x39大的数后符号由正变负,另一个数是加上比0x30小的值时是负数。这两个数是代码中初始化的 upperBoundlowerBound,然后加法之后获取其符号位判断即可
    int isAsciiDigit(int x) {
      int sign = 0x1<<31;
      int upperBound = ~(sign|0x39);
      int lowerBound = ~0x30;
      upperBound = sign&(upperBound+x)>>31;
      lowerBound = sign&(lowerBound+1+x)>>31;
      return !(upperBound|lowerBound);
    }
    

    7. conditional

    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) {
        int flag = ~!!x + 1;
        return (flag & y) | (~flag & z);
    }
    
    • 把flag构造为全0或者全1的来与y和z进行与。
    • 如果x非0,那么~!!x + 1就是全1;如果x是0,那么~!!x + 1就是全0

    8. isLessOrEqual

    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 diff = ~x + y + 1;
        int signX = (x>>31) & 0x1;
        int signY = (y>>31) & 0x1;
        int signD = (diff>>31) & 0x1;
        int sameSign = !(signX ^ signY);
        return (sameSign & !signD) | (!sameSign & signX);
    }
    
    • 虽然不能用减法,但是比较大小就是做差的过程。转换目标为y-x≥0,因为大于等于0的符号位都是0.
    • 首先用y-x=~x+y+1算出差的位级表示,但是这个结果是可能溢出的,需要判断是否溢出。
    • 如果x和y的符号一致,肯定是不会溢出的;如果溢出的话,那么y-x≥0就取决于x和y的符号了(他俩一定是相反的)

    9. logicalNeg

    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) {
        int com = ~x + 1;
        int signOrigin = (x>>31) & 0x1;
        int signCom = (com>>31) & 0x1;
        int sameSign = signOrigin ^ signCom ^ 0x1;
        return sameSign & (((x>>31) & 0x1) ^ 0x1);
    }
    
    • 基本思路就是,既然只有一个输入x,那么要么是对x进行变换后比较,要么是和固定值比较。
    • 把x和-x的符号进行比较,如果不同那么就输出0;如果相同且不是0x80000000就返回1。
    • 主要是要用异或实现对指定位的非操作
    • 其他答案
      • 还是利用符号位,只不过要简单一些。直接把x和-x的符号做或,如果为1就返回1,如果为0就返回0。使用右移31位,符号位为0就是0,符号位为1就是-1,加1即可
    int logicalNeg(int x) {
      return ((x|(~x+1))>>31)+1;
    }
    

    10. howManyBits

    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 sign = x>>31;
        int y = (sign & ~x) | (~sign & x);
        int b16 = (!!(y>>16))<<4;     //高十六位是否有1
        y = y>>b16;                   //如果有(至少需要16位),则将原数右移16位
        int b8 = (!!(y>>8))<<3;       //剩余位高8位是否有1
        y = y>>b8;                    //如果有,则右移8位
        int b4 = (!!(y>>4))<<2;
        y = y>>b4;
        int b2 = (!!(y>>2))<<1;
        y = y>>b2;
        int b1 = !!(y>>1);
        y = y>>b1;
        int b0 = y;
        return b16 + b8 + b4 + b2 + b1 + b0 + 1;
    }
    
    • 位运算也不定不能用二分,这道题就相当于层层二分了。
    • 对于正数,最少位数为最高位的1加一个符号位;对于负数,最少位数为最高位的0加一个符号位。所以可以直接把负数转成补码处理。
    • 用两个非!!来测试范围内有没有1,层层二分,如果范围内有就位移并加上这个范围。

    11. floatScale2

    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

    • 求2乘以一个浮点数
    unsigned floatScale2(unsigned uf) {
        unsigned sign = uf >> 31;
        unsigned exp = (uf >> 23) & 0xFF;
        unsigned frac = uf & 0x7FFFFF;
        if(exp==0xFF) {
            return uf;
        } else if(exp!=0) {
            exp += 1;
        } else {
            if((frac>>22)&0x1) {
                frac = frac & ~0x800000;
                exp = 1;
            }
            frac = frac<<1;
        }
    
        return (sign<<31) | (exp<<23) | frac;
    }
    
    • 区分无穷/NaN,返回其本身。问题是其实无穷也应该返回NaN,但是直接返回无穷不会报错。
    • 规格化数直接exp加一;非规格化数如果最高位是1就要规格化。

    12. floatFloat2Int

    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 f) {
        unsigned sign = f >> 31;
        unsigned exp = (f >> 23) & 0xFF;
        unsigned frac = f & 0x7FFFFF;
        unsigned e, half, round, rest;
        int k = 23;
        int bias = 127;
        if(exp==0xFF) {
            return 0x80000000;
        }
        if(exp < bias) {   //(1<<(8-1))-1
            return 0;
        } else {
            frac |= 0x800000;
            e = exp - bias;
            if(e<k) {
                half = 1<<(k - e - 1);
                round = frac & ((1<<(k - e)) - 1);
                rest = frac >> (k - e);
                if(round>half) {
                    rest += 1;
                } else {
                    if(round==half && (rest & 0x1)) {
                        rest += 1;
                    }
                }
            } else if(e<31) {
                rest = frac << (e - k);
            } else {
                return 0x80000000;
            }
        }
        if(sign) {
            rest = ~rest + 1;
        }
        return rest;
    }
    
    • 比较麻烦的是处理向偶数舍入

    13. floatPower2

    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

    • 输入一个整数x,返回他的2x2^x2x
    unsigned floatPower2(int x) {
        int k = 23;
        int bias = 127;
        unsigned frac;
        unsigned exp;
        if(x>bias) {
            return 0x7F800000;
        } else if(x>=-bias) {
            exp = x + bias;
            frac = 0;
        } else if(x>=-bias-k+2) {
            exp = 0;
            frac = 1<<(bias+k-2+x);
        } else {
            return 0x0;
        }
        return (exp<<k) | frac;
    }
    
    • 比较麻烦的是要处理非规格数。此外需要把超时时间调大一点,不然会运行不完。
    来源与结束于否定之否定。
  • 相关阅读:
    用心合作
    添加IE右键菜单 以 调用和运行 自己的程序或文件
    VS2005 My.Computer.Registry 对象 操作注册表 简单示例
    项目经理职业生涯
    Visual studio.NET单元测试中Assert类的用法(转载)
    如何正确理解自动化测试?(转载)
    浅析ASP.NET单元测试中的调试(转载)
    软件项目质量管理实战总结(转)
    主题:小公司如何做项目管理(转)
    什么是“极限编程”?(转载)
  • 原文地址:https://www.cnblogs.com/iwehdio/p/15679889.html
Copyright © 2020-2023  润新知