这里是新手Ayanokoji暑假偷卷ICS Lab的踩坑日记。【Data Lab篇】
用的是cmu官网上的lab片段。
1.BitXor Puzzle
int bitXor(int x, int y) {
return ~(~x & ~y) & ~(x & y); //De Morgen
}
使用De Morgen定律易得。
2.TMin Puzzle
int tmin(void) {
return 1<<31;
}
简单。
3.isTmax Puzzle
int isTmax(int x) {
return !((~x)^(x+1))&(!!(~x));//后面为了判断是否是-1
}
因为当时刚开始学,所以迷迷糊糊的,这个其实绕了远路。!((~x)^(x+1))在x为Tmax或者-1时运算结果时0,再用后面半段排除掉-1的情况即可。
4.allOddBits Puzzle
int allOddBits(int x) {
return !((~x>>1)&(0x55+((0x55)<<8)+((0x55)<<16)+((0x55)<<24)));
}
依然绕了远路,将x取反后右移一位,那么所有的偶数位应该是0,再与0x55555555取和,应该得到0,最后使用boolean not即可。
5.negate Puzzle
int negate(int x) {
return (~x)+1;
}
简单。
6.isAsciiDigit Puzzle
int isAsciiDigit(int x) {
int lower_bound = 0x30; // 0
int upper_bound = 0x39; // 9
int is_greater_or_equal_lower = !((x + (~lower_bound + 1)) >> 31);
int is_less_or_equal_upper = !((upper_bound + (~x + 1)) >> 31);
return is_greater_or_equal_lower & is_less_or_equal_upper;
}
思路比较直接,先把0和9表示出来,再作差观察符号位是0还是1即可。
7.conditional Puzzle
int conditional(int x, int y, int z) {
int mask = ~(!!x)+1;
return ((mask&y)|(~mask&z));
}
比较经典的做法。如果x为0,其掩码全0,否则其掩码全1。Boolean not 在这里发挥了显著的作用。
8.isLessOrEqual Puzzle
int isLessOrEqual(int x, int y) {
int t = x+(~y+1);
return !(t) | !!((t>>31)&1);
}
先作差,看是否为0,符号位是正还是负。
9.logicalNeg Puzzle
int logicalNeg(int x) {
return ((((~x + 1) | x)>>31)+1);//只有0的取反前后首位都为0
}
正如注释所说,只有+0与-0的首位都是0,否则符号位必有一正一负。
10.howManyBits Puzzle
int howManyBits(int x) {
int temp = x ^ (x << 1);
int bit_16,bit_8,bit_4,bit_2,bit_1;
bit_16 = !!(temp >> 16) << 4;
temp = temp >> bit_16;
bit_8 = !!(temp >> 8) << 3;
temp = temp >> bit_8;
bit_4 = !!(temp >> 4) << 2;
temp = temp >> bit_4;
bit_2 = !!(temp >> 2) << 1;
temp = temp >> bit_2;
bit_1 = !!(temp >> 1);
return 1 + bit_1 + bit_2 + bit_4 + bit_8 + bit_16;
}
暴力做法,分别以2^n为界限考虑即可。
11.floatScale2 Puzzle
unsigned floatScale2(unsigned uf) {
unsigned sign = uf>>31;
unsigned exp = (uf>>23) &0xff;
unsigned frac = uf& 0x7FFFFF;
if(exp == 0xFF){
return uf;
} //NaN
if(exp == 0){
return (sign<<31)|(frac<<1);
}
else{
exp++;
if(exp == 0xFF){
return (sign<<31)|0x7F800000;//Overflow
}
else{
return (sign<<31)|(exp<<23)|frac;
}
}
}
代码逻辑已经比较清楚了,不用赘述。
12.floatFloat2Int Puzzle
int floatFloat2Int(unsigned uf) {
unsigned sign = uf>>31;
unsigned exp = uf>>23 & 0xFF;
int frac = (uf & 0x7fffff) | 0x800000;//恢复前导1
int e = exp - 127;
if (e < 0) {
return 0;
}
if (e > 31) {
return 0x80000000; // 无穷大或者nan
}
if (e > 23) {
frac <<= (e - 23);
} else {
frac >>= (23 - e);
}
if (!((sign) ^ (frac >> 31))) {
return frac;
}
if (frac >> 31) {
return 0x80000000;// 符号位变化,且当前符号为负,说明溢出
}
return ~frac + 1;
}
本人觉得整个lab最麻烦的一道题,狠狠拷问了关于IEEE浮点数规则的理解。先移动小数点,再判断移动后的数是否溢出。
13.floatPower2 Puzzle
unsigned floatPower2(int x)
{
signed posinf = 0x7F800000;
int exp = 127+x;//这实际上是小数全为0的float形式
if(exp>=255){
return posinf;
}
if(exp<=0){
return 0;
}
else{
return exp<<23;
}
}
比较简单。这个puzzle是一个比较简单的浮点数形式,也即exp位非0,小数位全为0。我们只需要判断exp位是否可以表示,是否会溢出即可。
至此,Datalab的所有问题都解决完毕。放一个autograder的截图如下:
那么我们下周Bomblab见!