CSAPP Lab1-datalab

实验环境:Clion + WSL2 UBuntu 20.04

1. bitXor

此函数求x和y的异或值,只能使用~和&。考虑到执行异或操作得1的情况(1 ^ 0 = 1,0 ^ 1 = 1),而与操作得1的情况只有1 & 1 = 1,所以 x&y 只有两数都是1的位结果是1,而异或需要的各位不相同的情况在与操作结果的0里,所以在此将x&y的结果取反。而此时取反后,为1的值中还有0&0的结果,所以要考虑将此去除掉。和前面的想法相同,如果获得 ~( ~x & ~y)则会得到 1 & 1的结果。此时这两个结果中共同为1的是x和y中都是1的情况,不同的分别是 0 & 0 和 1 & 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);
}

2. tmin

负数为补码,最小的数为1000 0000 0000 0000 0000 0000 0000 0000(-2147483648),根据定义编码如下

int tmin(void) {
  return 1 << 31;
}

3.isTmax

用异或来判断等于!((~(x+1)^x)) 判断这个是否为1即可判断是否为最大值,这里有一个例外就是x=-1 由于-1=1111 他利用上面的式子判断也符合,故要特判-1 利用!!(x+1) 这个操作-1和最大值并不相同

int isTmax(int x) {
  return ! ( ~( x + 1 ) ^ x ) & !!(x + 1) ;
}

4.allOddBits

此题目为判断奇数为是否全为1,如果全为1则返回1,否则返回0。因此只判断x & 0xAAAAAAAA 是否等于 0xAAAAAAAA,由于不能使用 == 号,则使用a == b 等价于 ! (a ^ b)。又因为只能使用0x00-0xff大小的数,因此需要从0xAA进行移位操作进行构造0xAAAAAAAA

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

5.negate

负数编码为补码形式,为原码按位取反+1,因此对于正数变负数的方法为按位取反+1,对于一个负数来说,计算机中存储的是其补码,而补码的补码是原码,而~n+1就是先将负数的补码,变成原码,这个时候在将符号位变为0的过程

int negate(int x) {
  return ~x + 1;
}

6.isAsciiDigit

根据题意是要判断0x30-0x39之间的字符,首先判断高位4比特,由于都为0100,则只需要比对是否都为0100即可。观察低位4比特位为0000-1001,最大为0x09,则0x09减去第四位,如果为非负数,则表示在范围内,如果为负数,则表示不在范围内,由于只能使用+号,则将数值取反进行相加进行比较

int isAsciiDigit(int x) {
    int first = x >> 4;
    int second = x & 0x0f;
    return !((first ^ 0x03) | (((0x09 + (~second + 1)) >> 31) ^0x00));
}

7.conditional

本题是使用位运算实现三目运算符,考虑一个数和一个全0的数做按位与运算结果是全0,和一个全1的数进行与运算结果是这个数本身,所以当x为0的时候,应该输出z并且将y屏蔽,则应该是( x & y) | (~x & z)。此时应该考虑x不为0时该如何处理,由上述式子得知,应当将不为0的数统一变为0的反码,及0xffffffff,因此将x与0作比较,并将x转换

int conditional(int x, int y, int z) {
    int flag = !(x ^ 0);	// x为0的时候,flag = 1
    x  = ~flag + 1;	// flag = 1 的时候,此时x变为0xffffffff,即x此时表示不为0时的状态
    return( ~x & y) | (x & z);
}

8.isLessOrEqual

x<=y的判断分为符号相同和符号不同,如果是符号相同,需要判断y-x是否>=0,如果是符号不同,需要判断x和y的符号的差进行求值
ps:右移操作如果最左边为为1,则会填充1,需要&1进行取值

int isLessOrEqual(int x, int y) {
    int fx = (x >> 31) & 1;   // x的符号
    int fy = (y >> 31) & 1;   // y的符号
    //      符号相同 y - x >= 0                     符号不同 fy - fx < 0 为真
    return   ((!(fx^fy )) & !((y + (~x + 1)) >> 31)) | ((fy + ~fx + 1) >> 31) & 1;
}

9.logicalNeg

除了0与0x80000000这两个数,每个数与其补码的交为0xffffffff,而0和0x8000000这两个数的补码为这个数本身,由于所求的是逻辑非,0返回1,非零返回0,而0和其他数字经过计算后,只有符号位不同,0的符号位0,其余数都为1,所以获得符号位,并且+1控制返回值

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

10.howManyBits

int howManyBits(int x) {
    int sign,b16,b8,b4,b2,b1,b0;
    sign = x >> 31;
    // 将 x 转换为正数,这样只要判断最高位 1 出现的位置即可
    x = (sign & ~x) | (~sign & x);
    // 判断高16位是否存在 1,如果有就右移 x
    b16 = (!!(x >> 16)) << 4;
    x = x >> b16;
    // 判断高 8 位是否存在 1,如果有就右移 x
    b8 = (!!(x >> 8)) << 3;
    x = x >> b8;
    // 判断高 4 位是否存在 1,如果有就右移 x
    b4 = (!!(x >> 4)) << 2;
    x = x >> b4;
    // 判断高 2 位是否存在 1,如果有就右移 x
    b2 = (!!(x >> 2)) << 1;
    x = x >> b2;
    b1 = !!(x >> 1);
    b0 = x >> b1;
    return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}

11. floatScale2

根据浮点数的定义,如果exp=255 并且尾数非0 就是NaN 直接return 就好 其次如果frac 全为0 那么则表示无穷大 这两种情况都可以直接return,如果exp=0 则表示非规格化数,那么我们直接返回uf*2,如果exp!=0 && !=255 那么表示规格化数,那么我们的修改就先把exp+1

unsigned floatScale2(unsigned uf) {
    int exp = (uf & 0x7f800000) >>23;
    int sign = uf & (1 << 31);
    int frac = uf & 0x7fffffff;
    if(exp == 0) { return (frac << 1) | sign; }
    if(exp == 255) {return uf;}
    exp = exp + 1;
    return (exp<<23) | (uf & 0x807fffff);

12. floatFloat2Int

如果原浮点值为0则返回0;如果真实指数大于31(frac部分是大于等于1的,1<<31位会覆盖符号位),返回规定的溢出值0x80000000u;如果exp<0,结果为0,则返回0。剩下的情况:首先把小数部分(23位)转化为整数(和23比较),然后判断是否溢出:如果和原符号相同则直接返回,否则如果结果为负(原来为正),否则原来为负,结果为正

int floatFloat2Int(unsigned uf) {
    int exp = ((uf & 0x7f800000) >>23) - 127 ;
    int sign = (uf >> 31) & 1;
    int frac = uf & 0x007fffff;
    if(exp < 0) return 0;
    else if(exp >= 31) {
        return 0x80000000u;
    }
    else {
        frac = frac | (1 << 23);
        if(exp < 23) {
            frac = frac >> (23-exp);
        }else{
            frac = frac << (exp-23);
        }
    }
    if(sign)    return -frac;
    else return frac;
}

13.floatPower2

根据浮点数定义,先算指数,如果指数小于0,则表示值为0,如果大于255,则表示无穷大,如果在这之前,则为2^x的值,为正数且底数为1.000,则只需要将指数移位即可

unsigned floatPower2(int x) {
    int exp = 127 + x;
    if(exp <= 0)    return 0;
    if(exp >= 255)  return 0xff << 23;
    return exp << 23;
}

实验结果

在这里插入图片描述

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值