data lab是一个考察整数位运算技巧和实数的浮点数表示位格式的lab,而且还有能使用的符号和符号数量限制。
这些题目自己做下来有一些智力游戏的感觉,而且要考虑的边界情况很多(尤其是0x80000000),有时候自己不知道做错了哪里经常需要利用lab给的举反例工具来举反例看自己错在哪里,然后再修改调试。但是这样一来次数多了,做完以后自己晕乎乎地都不知道对了没有,不像bomb lab做的时候晕乎乎,做完后想一想能清楚很多。所以做完以后我没有急着总结写报告,而是等了很久趁现在空了下来,我回忆了一下我还记得什么,我到底从中学到了什么。
做完data lab有一种很浓的智力游戏的感觉,虽然这个lab设计地很好很精巧,但是还是要承认,在对数据的二进制表示有一定熟练度以后这个lab大部分题目的应用真的不是很大,练习的技能似乎与实战脱节,至于追求更少op数,我觉得完全是对自己的智力的挑战,为了挑战困难的愉悦而奋斗,实际意义不大。(不过我很崇拜这些op数到了80-的人,一来他们真的很厉害,而来虽然这个没有实际太大意义,可是大学CS学习的东西虽然实用,更重要的内功的积累,所以学习不能太功利,而且享受这些看似无用的东西,遵从自己的兴趣,才能有一段美好的大学生活吧。)
但是其中还有几点很值得我们学习,一是(个别)的整数位运算技巧,比如取整数低位,在树状数组里用得很多,二是浮点数题目,让我们亲自实现加深了我们对IEEE标准的理解。
整数运算技巧主要有:掩码技术,整数运算溢出判断,异或应用,二分统计位级信息等技术。
但是还有一些lab里没有涉及的整数运算技巧,我觉得很重要,网上有很多文章,如果以后要面试什么的之前可以先看一看。
//1
/*
* thirdBits - return word with every third bit (starting from the LSB) set to 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 1
*/
int thirdBits(void) {
int x=0x49;//1001001(8)
x=x|(x<<9);//001001001001001001(18)
x=x|(x<<18);//(36)
return x;
}
/*
* isTmin - returns 1 if x is the minimum, two's complement number,
* and 0 otherwise
* Legal ops: ! ~ & ^ | +
* Max ops: 10
* Rating: 1
*/
int isTmin(int x) {
int t=x+x;
return !(t|(!x));
}
//2
/*
* isNotEqual - return 0 if x == y, and 1 otherwise
* Examples: isNotEqual(5,5) = 0, isNotEqual(4,5) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 6
* Rating: 2
*/
int isNotEqual(int x, int y) {
return !!(x^y);
}
/*
* anyOddBit - return 1 if any odd-numbered bit in word set to 1
* Examples anyOddBit(0x5) = 0, anyOddBit(0x7) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 12
* Rating: 2
*/
int anyOddBit(int x) {
x|=x>>16;
x|=x>>8;
return !!(x&0xaa);
}
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
//3
/*
* 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 result=y;
int delta=z+~y+1;
int notx=((!x)<<31)>>31;
result+=delta¬x;
return result;
}
/*
* subOK - Determine if can compute x-y without overflow
* Example: subOK(0x80000000,0x80000000) = 1,
* subOK(0x80000000,0x70000000) = 0,
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int subOK(int x, int y) {
int ans=x+~y+1;
return !(((x^y)&(ans^x))>>31);
}
/*
* isGreater - if x > y then return 1, else return 0
* Example: isGreater(4,5) = 0, isGreater(5,4) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isGreater(int x, int y) {
int s=(y+~x+1)>>31;
int sx=x>>31;
int sy=y>>31;
return (s&1)^(!(s^sx)&(s^sy));
}
//4
/*
* bitParity - returns 1 if x contains an odd number of 0's
* Examples: bitParity(5) = 0, bitParity(7) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 4
*/
int bitParity(int x) {
x^=x>>16;
x^=x>>8;
x^=x>>4;
x^=x>>2;
x^=x>>1;
return x&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 flag=!(!x|!(x+1));
int s=x>>31;
int x1=x^s;
int x2=x1|(x1>>1);
int x4=x2|(x2>>2);
int x8=x4|(x4>>4);
int x16=x8|(x8>>8);
int x32=x16|(x16>>16);
int l=x32^(x32>>1);
int g16=l>>16;
int l16=(g16|l)&((1<<16)+(~0));
int g8=l16>>8;
int l8=(g8|l16)&0xff;
int g4=l8>>4;
int l4=(g4|l8)&0xf;
int g2=l4>>2;
int l2=(g2|l4)&0x3;
int g1=l2>>1;
int l1=(g1|l2)&1;
return ((!!g16)<<4)+((!!g8)<<3)+((!!g4)<<2)+((!!g2)<<1)+(!!g1)+1+flag;
}
//float
/*
* float_half - Return bit-level equivalent of expression 0.5*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 float_half(unsigned uf) {
unsigned s=uf&0x80000000;
unsigned exp=uf&0x7f800000;
int lsb=((uf&3)==3);
if (exp==0x7f800000)
return uf;
if (exp<=0x800000)
return s|(((uf^s)+lsb)>>1);
if (exp)
return (uf-0x800000);
}
本次data lab是以下三个题,尤其要注意的是float_i2f这个题先左移整数在统一右移处理避开了
左移还是右移的分类讨论,也避开了是否round的分类讨论,统一处理了,何其优雅!这个思路来自网络看了别人的文章加上我对IEEE标准的理解。还有一些round_to_even的细节,值得回味。
//float
/*
* float_half - Return bit-level equivalent of expression 0.5*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 float_half(unsigned uf) {
unsigned s=uf&0x80000000;
unsigned exp=uf&0x7f800000;
int lsb=((uf&3)==3);
if (exp==0x7f800000)
return uf;
if (exp<=0x800000)
return s|(((uf^s)+lsb)>>1);
if (exp)
return (uf-0x800000);
}
/*
* float_i2f - Return bit-level equivalent of expression (float) x
* Result is returned as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point values.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned float_i2f(int x) {
unsigned sign=0,frac;
int exp,flag,last,round,stick;
if (x==0)
return 0;
if (x<0)
sign=0x80000000;
if (sign)
frac=-x;
else
frac=x;
exp=158;
while (!(frac&0x80000000)) {
exp--;
frac<<=1;
}
last=(frac>>8)&1;
round=(frac>>7)&1;
stick=frac&0x7f;
flag=(round&&stick)||(round&&!stick&&last);
frac=(frac<<1)>>9;
frac+=flag;
if (frac>=0x800000) {
frac=((frac+0x800000)>>1)-0x800000;
exp+=1;
}
return (sign|(exp<<23)|frac);
}
/*
* float_f2i - 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 float_f2i(unsigned uf) {
int sign=uf>>31;
int exp=(uf>>23)&0xff;
int frac=uf&0x007fffff;
int right=157-exp;
int abs;
if (exp<0x7f)
return 0;
if (exp>157)
return 0x80000000;
abs=(0x40000000+(frac<<7))>>right;
if (sign)
return -abs;
else
return abs;
}