从CSAPP课程主页下载datalab实验所需的压缩包。下图说明本次实验需要补齐的函数名列表。
/*
* 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));
}
解题思路:
利用a⊕b = (¬a ∧ b) ∨ (a ∧¬b)公式和德-摩根定律得到上面的代码.
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 0x1<<31;
}
解题思路:
首先明确32位整数最小值的二进制为0x80000000.
/*
* isTmax - returns 1 if x is the maximum, two's complement number,
* and 0 otherwise
* Legal ops: ! ~ & ^ | +
* Max ops: 10
* Rating: 1
*/
int isTmax(int x) {
int res = !((~(x+1))^x) & !!(~x);
return res ;
}
解题思路:
首先明确32位整形最大值为0x7fffffff.由于题目中规定不能使用移位符号,
/*
* 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
*/
int allOddBits(int x) {
int mask = 0xAA | (0xAA<<8) | (0xAA<<16) | (0xAA <<24);
x = x & mask;
return !~(x>>1 | x);
}
解题思路:
首先要获取奇数位的信息,则有mask:0xAAAAAAAA.(十六进制A的二进制表示为1010).当奇数位全为1时,(x>>1 | x)则表示0xffffffff,反之,则不成立.
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
解题思路:
套基本公式
/*
* 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
*/
int isAsciiDigit(int x) {
return !((0x39 + (~x+1))>>31|(x+(~0x30+1))>>31)&0x1;
}
解题思路:
题目的等价表达式是"(0x39-x)>=0且(x-0x30)>=0".此时只需要判断符号位就能知道是否满足不等式(符号位为1表示不满足),这与函数输出的逻辑刚好相反(函数输出1表示满足整个表达式).最后利用的摩根定理得到上述代码.
/*
* 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 x1 = ~((~x +1)|x)>>31;
return (~x1 & y ) | (x1 & z);
}
解题思路:
题目让我们写一个条件选择符,当x为0x0时选择输出z,考虑利用零的相反数是零的性质解题.
/*
* 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 signx = x>>31 ;
int signy = y>>31 ;
int signal = signx ^ signy;
int exp = ((y+(~x+1))>>31);
return ((signal&( (signx&0x1) | (signy&0x0) ) ) | (!signal&!exp ))&0x1;
}
解题思路:
等价为y-x>=0,有四类情况分类讨论
/*
* 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) {
//一个数的相反数等于自身的只有零
return ~(((~x+1)|x)>>31)& 0x1;
}
/* 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
*/
/*
* -5 1,000_0000_0000_0000_0000_0000_0000_0101 1111_1111_1111_1111_1111_1111_1111_1011
* 5 0,000_0000_0000_0000_0000_0000_0000_0101
* */
int howManyBits(int x) {
int mask1 = 0x1 | 0x1<<8 | 0x1<<16 | 0x1<<24;
int mask2 = (x&(0x1<<31))>>31;
int sum = 0;
int tmp = x ^ mask2;
tmp |= tmp >>1;
tmp |= tmp >>2;
tmp |= tmp >>4;
tmp |= tmp >>8; sum += (tmp >>2) & mask1;
sum += (tmp >>3) & mask1;
sum += (tmp >>4) & mask1;
sum += (tmp >>5) & mask1;
sum += (tmp >>6) & mask1;
sum += (tmp >>7) & mask1;
return (sum & 0xff) + ((sum>>8) & 0xff) + ((sum>>16) & 0xff) + ((sum>>24) & 0xff) + 1;
}
解题思路:
忽略符号位,把最高位的1右侧所有位都置为1,再查询1的个数,最中的结果再加1.
/*
* 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
*/
unsigned floatScale2(unsigned uf) {
unsigned sign = uf & 0x80000000;
unsigned exp = uf & 0x7f800000;
unsigned frac = uf & 0x7fffff;
if(exp ^ 0x7f800000){//exp!=255
if(!exp){//exp==0
frac <<= 1;//此时为非规格化数,尾数无隐含常数1,直接左移1位即可
}
else{//0
exp += 0x800000;//乘2
if((exp ^ 0x7f800000)==0){//判断乘2以后是否溢出
frac=0;//输出INF
}
}
}
return sign | exp | frac;
}
解题思路:
接下来的三题,让我深刻理解了"数据类型规定了数的为宽,和相应的操作方法"这句话的意义.下图表示了浮点数的位级示意图.从图可以知道解答lab中关于浮点数的题目.
/*
* 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 uf) {
unsigned INF = 0x80000000;
//提取符号位
int s = (uf >>31) & 0x1;
//提取阶码
int E = uf >> 23 & 0xff;
//提取阶数
int e = E -127;
if (uf == 0) return 0;
//因为输入是规格化浮点数,转化为整数时第23位需要为1
uf &= 0x00ffffff;
uf |= 0x00800000;
//浮点数中0~22位的数字逻辑上位小数,当看作整数时相当于乘以了2^23
//阶码为255或阶数大于等于32时,视为溢出,输出INF.因为int为32bit,超出即溢出,且考虑1bit符号位
if ((uf & 0x7f80000) == 0x7f80000 || e>= 32) return INF;
if (e<0) return 0;//若为小数,返回零
//无符号数的移位运算都是逻辑移位
if (e <= 23) uf >>= 23 - e;//因为浮点数尾数宽度为23bit,位数小于等于23,尾数位右移.这是一种舍入方式
else uf <<= e-23;//位数大于23,尾数左移
//当符号位为负数,uf要取值为它的相反数
if(s) uf = ~uf + 1;
return uf;
}
/*
* 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
*/
unsigned floatPower2(int x) {
//int INF = 0xff << 23;
int INF = 0x7f800000;
int exp = x + 127 ;
//溢出
if(exp >= 255) return INF;
//为小数时
if(exp <= 0) return 0;
return exp<<23;
}