CSAPP Lab官网
CUM Intro to Computer Systems课程官网
本文是对CSAPP3.0实验一Data Lab的实验记录,主要参考了这篇文章:https://zhuanlan.zhihu.com/p/59534845?utm_source=qq
题目列表
题解
bitXor
“异或”是两数不同则为1,相同则为0。故返回1时,两数不能同时为0,也不能同时为1:~(~x&~y)&~(x&y)
,也可以表达为x=0,y=1或y=0,x=1:(~x&y)|(~y&x)
。本题不能使用|
符号,故选择第一种。
/*
* 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);
}
tmin
返回INT_MIN。
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return (1 << 31);
}
isTmax
判断整数类型是否等于INT_MAX。当x=0xffffffff
时,i=x+1=0
,x+i==0xffffffff
,与x==INT_MAX
时情况一样,应该排除。
/*
* 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 i = x + 1; // INT_MAX + 1 = INT_MIN, 0x80000000
x += i; // -1, 0111... + 1000... = 1111...
x = ~x; // 0
i = !i; // exclude x == 0xffff...
x += i; // exclude x == 0xffff...
return !x;
}
allOddBits
如果所有的奇数位为1,就返回1;否则,返回0。注意这道题不能使用超过255的整型常量。
/*
* 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);
mask = mask + (mask << 16);
return !((mask & x) ^ mask);
}
negate
返回整数的负数。
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x + 1;
}
isAsciiDigit
如果x
是字符'0'~'9'
之间的数就返回1,否则返回0。
/*
* 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) {
int sign = 1 << 31;
int upperBound = ~(sign | 0x39);
int lowerBound = ~0x30 + 1; // -0x30
upperBound = sign & (upperBound + x); // 如果x>0x39,则upperBound + x会向符号位进位,则符号位为1
lowerBound = sign & (lowerBound + x); // 如果x<0x30,则lowerBound + x == x - 0x30 < 0,得到负数,符号位为1
return !(upperBound | lowerBound); // 只要存在x>0x39或x<0x30,则返回0
}
conditional
实现条件语句,如x ? y : z
。
/*
* 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) {
x = !!x; // 将x值设为0或1
x = ~x + 1; // x的位级为全0或全1
return (x & y) | (~x & z);
}
isLessOrEqual
判断x<=y
是否成立。如果x,y
同号,则y-x>=0
时成立;否则x,y
异号,正数较大,故x
为负数时成立。
/*
* 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 negX = ~x + 1; // -x
int addX = negX + y; // y - x
int checkSign = (addX >> 31) & 1; // y-x的符号位 neg:1, pos:0
int xSign = (x >> 31) & 1; // sign of x
int ySign = (y >> 31) & 1;
int bitXor = xSign ^ ySign; // x,y是否同号,同号为0,异号为1
return ((!bitXor) & (!checkSign)) | (bitXor & xSign);
}
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) {
// 利用算术右移,符号位填充高位
// 除0外的任何数(包括TMin),和它的负数取或,符号位均为1
// 故算数右移之后为0xffffffff
return ((x | (~x + 1)) >> 31) + 1;
}
howManyBits
补码表达x
需要多少位。需要1位记录符号位,当x>=0
时,找到最高的1位;当x<0
时,找到最高的0位,将该位记为第n位,n+1
即为所求结果。
/* 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 b16, b8, b4, b2, b1, b0;
int sign = x >> 31; // 如果是负,则右移之后32位全为1
x = (sign & ~x) | (~sign & x); // 如果x为负,则按位取反,找最高的0位改为找最高的1位即可
// 二分法找到最高位的1
b16 = !!(x >> 16) << 4; // 高16位里是否有1
x = x >> b16; // 如果有,右移16位
b8 = !!(x >> 8) << 3; // ! 优先级大于 <<
x = x >> b8;
b4 = !!(x >> 4) << 2;
x = x >> b4;
b2 = !!(x >> 2) << 1;
x = x >> b2;
b1 = !!(x >> 1);
x = x >> b1;
b0 = x;
return b16 + b8 + b4 + b2 + b1 + b0 + 1; // +1是符号位
}
floatScale2
返回2*f
的位级表示。
/*
* 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 >> 31;
unsigned exp = uf >> 23 & 0xff;
if(exp == 0) return (uf << 1) | sign << 31;
if(exp == 255) // NaN and oo
return uf;
exp++;
if(exp == 255) return 0x7f800000 | sign << 31; // +-oo
return (exp << 23) | (uf & 0x807fffff);
}
floatFloat2Int
将浮点型转化为整型。此题和课本中家庭作业第2.96题一样。注意将sign,exp,frac
都设为int
而不是unsigned
。
/*
* 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) {
int sign = uf >> 31;
int exp = (uf >> 23 & 0xff) - 127; // E = e - bias
int frac = (uf & 0x007fffff) | 0x00800000; // M = 1 + f,因为在整数范围内的都是规格化数
// 正负零都是零
if(!(uf & 0x7fffffff)) return 0;
// 超出整数范围
if(exp > 31) return 0x80000000u;
if(exp < 0) return 0;
// 移动frac,即 V = 2^E * M
if(exp > 23) frac <<= (exp - 23);
else frac >>= (23 - exp);
// 判断符号
if(!((frac >> 31) ^ sign)) return frac;
else if(frac >> 31) return 0x80000000u; // 溢出
else return ~frac + 1; // -frac
}
floatPower2
返回2^x
的位级表示。此题和家庭作业第2.90题一样。
/*
* 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){
unsigned exp, frac;
if(x < -149){
// Too small. Return 0.0
exp = 0;
frac = 0;
}else if(x < -126){
// Denormalized result
exp = 0;
frac = 1 << (x + 149);
}else if(x < 128){
// Normalized result
exp = x + 127;
frac = 0;
}else{
// Too big. Return +oo
exp = 255;
frac = 0;
}
return exp << 23 | frac;
}
进行测试时发现最后一题会超时。
解决方法是将btest.c
文件中TIMEOUT_LIMIT
由10改为了15(限制时间增加一点就没问题了。。因为实在找不到其他解决方案了。。看了一些网友的题解和我的思路差不多。。还是会超时。。)
使用./driver.pl
命令可以查看使用的操作符个数。