CSAPP datalab1

Q1 bitxor

//1
/*

  • bitXor - x^y using only ~ and &
  • Example: bitXor(4, 5) = 1
  • Legal ops: ~ &
  • Max ops: 14
  • Rating: 1
    */
    分析:题目要求的是通过用取反~和&运算符实现异或运算,在网上找到了异或运算的真值表
    在这里插入图片描述
    然后通过本学期学的离散数学知识通过真值表将x^y使用与,或,非即对二进制进行取反,步骤如下
    x^y = (x ∨ y) ∧ (~x ∨ ~y) (第一行和第四行的和之积表达式)
    = (x ∧ ~y) ∧ ~(x ∧ y) (德摩根律)
    转换后再用c语言进行表达如下
    int bitXor(int x, int y) {
    int Xor = (x & ~y) & ~(x & y);
    return Xor;
    }

Q2 tmin

/*

  • tmin - return minimum two’s complement integer
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 4
  • Rating: 1
    */
    这道题目要求使用! ~ & ^ | + << >>运算符来实现最小补码值,而最小的补码值是1000 0000 0000 0000 0000 0000 0000 0000,也就是将1向左移位31位到符号位也就是第32位即可,代码如下
    int tmin(void) {
    return 1 << 31;
    }

Q3 isTmax

//2
/*

  • isTmax - returns 1 if x is the maximum, two’s complement number,
  • and 0 otherwise 
    
  • Legal ops: ! ~ & ^ | +
  • Max ops: 10
  • Rating: 1
    */
    此题是判断x是不是最大值
    而最大值加一则是二进制的最小值,但如果想证实一个数一定是Tmax,那么可以借助Tmax + 1 = Tmin来确定,因为它们是互为充要条件的。
    Tmax + 1 = Tmin 可以推出Tmax - Tmin + 1 = 0,而通过Tmax - Tmin + 1 = 0又可以推出Tmax + (-Tmin) + 1 = 0,最后推出max + Tmin +1=0,但是要排除x=-1的这种情况,代码如下
    int isTmax(int x) {
    int i = x + 1;
    x = x + i;
    x = -x;
    i = !i;
    x = x + i;
    return !x;
    }

Q4 allOddBits

此题目是要求判断奇数位上是否全是1;
/*

  • 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
    */
    这道题的关键在于找出掩码值0xAAAAAAAA,这个数字很特别,它保留了所有奇数位,而此道题的解题思路是先构造出这样一个掩码值然后使其与x相与来获取x奇数位的对应情况,接着通过与掩码值异或来判断x对应奇数位是否全为1,而此类题往往先找特殊掩码在进行判断,代码如下
    int allOddBits(int x) {
    int i = (0xAA << 8) | 0xAA;(首先获取0xAAAAAAAA作为此问题的掩码, 而且0xAA作为常数值是可以直接使用的)
    int j = (i << 16) | i;
    return !((x & j) ^ j);
    }

Q5 negate

这道题要求的是求相反
/*

  • negate - return -x
  • Example: negate(1) = -1.
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 5
  • Rating: 2
    */
    对任何补码,-a = (~a + 1),逆元的位的快速求解就是按位取反再加1,也就是根据-a = (~a + 1)得到:-x=~x+1,代码如下
    int negate(int x) {
    return (~x + 1);
    }

Q6 isAsciiDigit

此题是要判断x是否是大于0x30且小于0x39的数
//3
/*

  • 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
    */
    将满足条件的数字的二进制位全部列出来,如下所示:
    0011 0000
    0011 0001
    0011 0010
    0011 0011
    0011 0100
    0011 0101
    0011 0110
    0011 0111
    0011 1000
    0011 1001
    其他范围内的数值第3位均为0,且0~2位包含了所有可能的情况。这意味着它们可以被归并为一类,而将剩下的两个作为特例来处理,变量j、k就分别验证了0x38、0x39这两个特例的情况,剩下的就是将原值x右移三位,此时应该确保剩下来的值是0x6(110),这对应了剩下的情况,最终返回值为三个条件的或,意思是满足了其中一条即可。
    代码如下
    int isAsciiDigit(int x) {
    int j = !(x ^ 0x38); /特殊值0x38/
    int k = !(x ^ 0x39); /特殊值0x39/
    x = !((x >> 3) ^ 0x6);
    return x | j | k;
    }

Q7 conditional

此题要求进行x?y:z的运算
/*

  • conditional - same as x ? y : z
  • Example: conditional(2,4,5) = 4
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 16
  • Rating: 3
    */
    判断x为0或非0,使用!,得到1或0,+~0得到全0和全1,以此为掩码,代码如下:
    int conditional(int x, int y, int z) {
    int a = !x+~0; //x==0,a=0000;x!=0,a=1111
    return (a&y)|(~a&z);
    }

Q8 isLessOrEqual

/*

  • isLessOrEqual - if x <= y then return 1, else return 0
  • Example: isLessOrEqual(4,5) = 1.
  • Legal ops: ! ~ & ^ | + << >>
  • Max ops: 24
  • Rating: 3
    */
    判断0 < = y − x 0<=y-x0<=y−x,只用判断符号位是否为0,又− x = ∼ + 1 -x=\sim+1−x=∼+1,所以y − x = y + ∼ x + 1 = a y-x=y+\sim x+1= ay−x=y+∼x+1=a,判断a的符号位,为0返回1,但需要排除异号相减的情况,代码实现如下:
    int isLessOrEqual(int x, int y) {
    int s1 = x>>31;
    int s2 = y>>31;
    int s = s1^s2;
    int a = y+~x+1;
    int b = !(a>>31);
    return (!!(s&s1))|((!s)&b);
    }

Q9 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
    */
    当x!=0时,返回1,此时分为x<0和x>0两种情况:
    当x<0,此时x的符号位为1;而当x>0,此时x不为0,取补+1的符号位不为0
    代码实现如下:
    int logicalNeg(int x) {
    int a = ~(x>>31); (x<0, a=0;a=1)
    int b = ((~x+1)>>31)+1; (x>=0, x!=0, a=0; a=1)
    return a&b;
    }

Q10 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
*/
这道题没有做出了在网上找的思路:要搞清楚一个数补码最少需要多少位,必须得找出来正数中位于最高位的1在哪里,这一点很好理解。如果是负数,就要找负数中最高位的0在哪里,然后再+1(表示符号位),可以这样理解负数的负权重全部是由最高符号位贡献的,越大的负数越容易使用较小的位数表示,如果我们想表示更小的负数就必须增加位数,同时保证符号位为1,在负数的二进制表示中出现的最高位0是一种标志,意思是这里的正权重不用了,那么也可以确定表示此数无需更多的二进制位
所找的代码如下
int howManyBits(int x) {
/获取数字的符号位, 如果符号位为1,那么Sign也是1/
int Sign = x >> 31;

/如果是负数那么按位取反,如果是正数那么保持原值/
x = (Sign & ~x) | (~Sign & x);

/接下来就是寻找数字中最高位的1在哪里/
/*
以第一个式子为例,如果判断高16为仍有1存在,
那么低16位必须保留,不用考虑它们了,直接移掉
*/
int High16 = !!(x >> 16) << 4;
x = x >> High16;

int High8 = !!(x >> 8) << 3;
x = x >> High8;

int High4 = !!(x >> 4) << 2;
x = x >> High4;

int High2 = !!(x >> 2) << 1;
x = x >> High2;

int High1 = !!(x >> 1);
x = x >> High1;

int High0 = x;
return High16 + High8 + High4 + High2 + High1 + High0 + 1;
}

Q11 float_twice

/*

  • float_twice - 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
    */
    此题思路就是分类讨论分为规划数字和非规划数字
    1.当数字是非规格化数字时,只需要将Frac部分左移一位即可,如果有进位,那么就实现了从非规格化数到规格化数的平滑过渡。
    2.当数字是规格化数字时,因为Frac部分需要加上一个隐式的1,所以单凭左移一位无法获得对应的2倍关系,这时候只需要直接在Exp部分+1即可,但是要排除无穷大的情况,无穷大返回自身即可。NaN直接在进行运算之前直接剔除掉。
    代码如下
    unsigned float_twice(unsigned uf) {
    unsigned f = ~(uf|0x807fffff);
    if (f) {
    unsigned a = uf&0x7f800000;
    if (a) {
    unsigned u = uf+0x800000;
    if (~(u|0x807fffff)) {
    return u;
    }
    return u&0xff800000;
    }
    return (uf&0x80000000)|(uf<<1);
    }
    return uf;
    }
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值