csapp dataLab


Datalab


1.bitXor

  • Ops:7

  • 设计思路:

    • 由于异或运算的结果是相同取0,相异取1
    • 两个数相同的方式有2种:同为1 或 同为0
    • 计算 x&y 和 ~x&~y
    • 上面2个式子只有2个数不同的情况下,才均为0
    • 所以将其分别取反,再做与操作
  • 源代码

    int bitXor(int x, int y) {
      return (~(~x&~y)&~(x&y));
    }
    

2.evenBits

  • Ops: 4

  • 设计思路:

    • 目标是返回0x55555555
    • 只能创建8个bit的数字,故int k = 0x55
    • 将k左移8位得到0x5555
    • 再将其左移16位得到答案
  • 源代码

    int evenBits(void) {
      int k = 0x55;
          k = k<<8|k;
      return k<<16|k;
    }
    

3.fitsShort

  • Ops: 4

  • 设计思路:

    • 考虑到如果x可以表示为16—bit的2进制补码,则其31—15位数字全部都为1或者0
    • 先将x右移15位,将15位以下的内容全部移除
    • 由于int是32个bit再将ans向右移动16位,使其每个bit均为最高位,所以此时其每位要么均为1要么均为0
    • 通过异或操作判断是否ans是否每个位置都是1或都是0
    • 如果均为1或均为0,结果为0,逻辑非以后得到1
  • 源代码:

    int fitsShort(int x) {
      int ans = x>>15;
        return !((ans>>16)^ans);
    }
    

4.isTmax

  • Ops:6

  • 设计思路:

    • Tmax的特点是最高位为0,剩下位均为1
    • 观察发现 x+x+2得0
    • 而满足x+x+2得0的式子的数还有-1(0x11111111)
    • 所以排除-1的情况下取!即为答案
  • 源代码:

    int isTmax(int x) {
      return  !((x+x+2)|!(~x));
    }
    

5.fitsBits

  • Ops: 7

  • 设计思路:

    • 发现规律,如果能够表示的话,n-1位以前的元素都是1或者0
    • n+~1+1是为了得到n-1
    • 用异或来判断是否都为1或都为0
  • 源代码:

    int fitsBits(int x, int n) {
      x = x>>(n+~1+1);
      return !((x>>n)^x); 
    }
    

6.upperBits

  • Ops: 7

  • 设计思路:

    • 如果n=0,返回0;如果n!=0,将前n位重置为1,再返回该值
  • 源代码:

    int fitsBits(int x, int n) {
      x = x>>(n+~1+1);
      return !((x>>n)^x); 
    }
    

7.allOddBits

  • Ops: 7

  • 设计思路:

    • 根据题意 allOddBits = 0xAAAAAAAA,故先构造此数
    • 判断x的偶数位是否都为1
      • x&a将x只留下偶数位上的信息
      • 再与a异或后取否 判断是否均相同
  • 源代码:

    int allOddBits(int x) {
      int a = 0xAA;
      a = a|a<<8;
      a = a|a<<16;
      return !((x & a)^a);
    }
    

8.byteSwap

  • Ops: 16

  • 设计思路:

    • 首先将第m和n个byte提取出来
    • 由于一个byte是4个,所以将m和n乘8
    • 将x移位后与0xFF取交之后再复位即可将数值提取出来
    • 构造不包含m和n位byte的数字
    • 将三个式子求和即为结果
  • 源代码:

    int byteSwap(int x, int n, int m) {
      int n8 = n << 3;
      int m8 = m << 3;
      int a = ((x >> n8) & 0xFF) << m8;
      int b = ((x >> m8) & 0xFF) << n8;
      int c = (x & ~(0xFF << m8) & ~(0xFF << n8));
      return (a | b | c);
    }
    

9.absVal

  • Ops: 5

  • 设计思路:

    • 分开讨论,如果是非负数其值不变;如果是负数,先取反再加1
    • 负数31th bit是1,利用此特性来构造负数时加1
    • 利用k^0x00000000 = k、k^0xFFFFFFFF = ~k性质来构造负数取反、非负数不变
  • 源代码:

    int absVal(int x) {
    	return (x^(x>>31))+((x>>31)&1);
    }
    
    

10.divpwr2

  • Ops: 7

  • 设计思路:

    • 分类讨论:如果是正数直接移n位,如果是负数的话,由于编码方式不同需要修正结果
    • 对于负数而言,如果是偶数不影响结果,如果是奇数,结果会比正确结果小
    • 构造[0,n-1]区间全为1的数
    • 如果输入是负数就加上这个修正值
  • 源代码:

    int divpwr2(int x, int n) {
        return (x+(x>>31&((1<<n)+~0)))>>n;
    }
    
    

11.leastBitPos

  • Ops: 3

  • 设计思路:

    • ~x+1将所求的x中是1的位中权重最小的那个位以外的所有位取反了
    • 所以(~x+1)&x为答案
  • 源代码:

    int leastBitPos(int x) {
    	return (~x+1)&x;
    }
    
    

12.logicalNeg

  • Ops: 6

  • 设计思路:

    • 分类讨论:0和非0数
    • 0的最高位为0,而非零数和其相反数的最高位必然一个为0、一个为1
    • 将x转化为相反数:~x+1
    • x|~x+1的结果中只有x=0会使其最高位为0
    • 故当最高位是0时返回1,最高位是1时返回0
  • 源代码:

    int logicalNeg(int x) {
    	return ~((x|(~x+1))>>31)&1;
    }
    
    

13.bitMask

  • Ops: 7

  • 设计思路:

    • 根据题意将所需的bit全部置为1就好了
    • 由于题目要求当lowBit>highBit的时候返回0,故考虑将小于lowBit置为0以及大于highBit置为0
    • 将0xFFFFFFFF左移lowbit,将0xFFFFFFFF+(1<<(highbit+1))
    • 将2个式子取交便为答案
  • 源代码:

    int bitMask(int highbit, int lowbit) {
    	return ((~0)<<lowbit)&((~0)+(1<<highbit<<1));
    }
    
    

14.isLess

  • Ops: 10

  • 设计思路:

    • 注意到如果两个数字正负性相同,只需要比较两个数字二进制的大小
    • 而在正负性不同的情况下,正数大于负数
    • 计算出x-y,利用-y=~y+1,即m=x-y
    • 用x^y来看符号位是否相同
    • m&~yihuo来看若是相同符号情况下x-y的符号
    • x&yihuo用来看符号不同时x的符号
    • 因此上面两个式子相加后符号位就是答案
  • 源代码:

    int isLess(int x, int y) {
      int yihuo = x ^ y;
    	int m = x + ~y + 1;
    	return (((m & ~yihuo) + (x & yihuo)) >> 31) & 1 ;
    }
    
    

15.logicalShift

  • Ops: 8

  • 设计思路:

    • 题目要求用算术右移实现逻辑右移
    • 考虑到算术右移时补充的是符号位,而逻辑右移只会补充0
    • 因此只需要将右移后补充的位全部与0取交集就好,同时为了保证其它位不变,其他位应与1取交
    • 1<<(32+~n)<<1是为了防止左移32位出现未定义的行为
  • 源代码:

    int logicalShift(int x, int n) {
    	int m = (~0)+(1<<(32+~n)<<1);
      return (x>>n)&m;
    
    }
    
    

16.satMul2

  • Ops: 10

  • 设计思路:

    • 分类讨论,在没有溢出的情况下,直接输出x>>1,溢出的话
    • 用x*2和x的符号位的异或来判断是否溢出:相同不溢出,相异则溢出
    • 溢出的话要判断是正溢出还是负溢出:这由x*2的符号位决定
    • 用掩码overflow_mask来表示是否越界
    • 发现~Tmin = Tmax,所以利用Tmin和2*x的符号位来构造Tmin或者Tmax
  • 源代码:

    int satMul2(int x) {
        int x_mul_2 = x << 1;
        int overflow_mask = (x_mul_2 ^ x) >> 31;
        int tmin = 1 << 31;
        int x_mul_2_is_neg = x_mul_2 >> 31;
        return (~overflow_mask & x_mul_2) |
               (overflow_mask & (tmin ^ (x_mul_2_is_neg)));	
    }
    
    

17.subOK

  • Ops: 10

  • 设计思路:

    • t1和t2分别是x和y的符号位
    • 如果符号位相同做减法一定不会溢出
    • 如果符号位不同,可能溢出,也可能不溢出
    • 取cf为x-y的符号位
    • 如果x-y会溢出其符号位为0,不溢出则为1
    • 利用0xFFFFFFFF + 1 = 0构造返回结果
  • 源代码:

    int subOK(int x, int y) {
     		int t1 = x >> 31;
        int t2 = y >> 31;
        int t = t1 ^ t2;
        int cf = (x + (~y + 1)) >> 31;
        return (t & (t1 ^ cf)) + 1;
    }
    
    

18.bang

  • Ops: 6

  • 设计思路:

    • 由于~0 + 1 = 0
    • 因此只有当小x=0时,x|~x+1 = 0
    • 特别:只有此时其结果的符号位为0
  • 源代码:

    int bang(int x) {
      return ~((x|(~x+1))>>31)&1;
    }
    
    

19.bitParity

  • Ops: 11

  • 设计思路:

    • 考虑到如果有奇数个0,那么必然有奇数个1,反之,有偶数个0必然有偶数个1
    • 将32位依次做异或操作
    • 偶数个1的话结果为0,奇数个1的话结果为1
    • 使用如下方法,每次将答案保存在低位,每一次可以计算一半的位数
  • 源代码:

    int bitParity(int x) {
        x = x ^ (x >> 16);
        x = x ^ (x >> 8);
        x = x ^ (x >> 4);
        x = x ^ (x >> 2);
        x = x ^ (x >> 1);
        return x & 1;
    }
    
    

20.isPower2

  • Ops: 10

  • 设计思路:

    • 题目要求只有正数可以满足要求,因此在考虑x的位中只有一个1的时候要排除掉负数
    • 另外,注意到满足要求的x有如下性质:x&(x-1) = 0
    • 并且发现0也具有该性质,所以我们需要排除0和0x80000000的影响
    • 对于0x80000000我们可以利用符号位排除,对于0 可以用!!来排除
    • 于是用(~(x>>31)&(!!x))来矫正答案
  • 源代码:

    int isPower2(int x) {
      int ret = ((!(x&(x+~0))) & ((~(x>>31)&(!!x))));
      return ret;
    }
    
    
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值