一、实验目的
加深对定点数补码、无符号数和IEEE754短浮点数标准的理解,加深对定点数和浮点数加减运算的理解。
二、实验原理
1.位操作
2.定点数补码表示
3.浮点数IEEE754表示
三、实验步骤
1、打开vm运行Ubuntu进入lab1-handout.tar所在目录开始实验操作
2、解压代码框架:tar -xvf lab1-handout.tar
3、进入解压后的目录make编译生成可执行文件,看看多了几个文件
4、通过修改bits.c 完成题目
5、做完题后进入vm进行make编译,注意提示信息,看编译是否出错
6、然后通过dlc测试(语法检查):./dlc bits.c (简单语法检查) ./dlc -e bits.c(检查操作运算符是否符合需求)
7、如果步骤6通过后,进行btest测试:./best (检查bits.c文件中所有函数功能,如果失败则给出测试用例)
8、修改答案,通过修改bits.c里的代码,继续进行步骤5、6、7
四、实验内容
1.代码及编程思路
(1)
- lsbZero - set 0 to the least significant bit of x
- Example: lsbZero(0x87654321) = 0x87654320
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 5
- Rating: 1
思路:x右移一位把最低有效位舍去,再左移把其余的数还原的原位上。
int lsbZero(int x) {
x=x>>1;
x=x<<1;
return x;
}
(2)
- TMax - return maximum two’s complement integer
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 4
- Rating: 1
思路:int最大值为0x7fffffff。最高位为0,其余为1,即10000000000000000000000000000000。再取反,即01111111111111111111111111111111,符号位为0,其余为1,是最大正整数。因此我们先创建一个最高位为1,其余0的数,然后对其取反。
int tmax(void) {
return ~(1<<31);
}
(3)
- isZero - returns 1 if x == 0, and 0 otherwise
- Examples: isZero(5) = 0, isZero(0) = 1
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 2
- Rating: 1
思路:因为非零取非为0,0取非为1,直接 !x 即可。
int isZero(int x) {
return !x;
}
(4)
- isNegative - return 1 if x < 0, return 0 otherwise
- Example: isNegative(-1) = 1.
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 6
- Rating: 2
思路:x<0即最高位为1移31为即为11111111111111111111111111111111(即为-1)取反+1即为1,x>0即最高位为0移31为即为00000000000000000000000000000000(即为0)取反+1为0。int型最高位为1时,这个数为负数。因此我们只要提取最高位的值即可。
int isNegative(int x) {
return !!(x>>31);
}
(5)
- sign - return 1 if positive, 0 if zero, and -1 if negative
- Examples: sign(130) = 1
-
sign(-23) = -1
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 10
- Rating: 2
思路:在isNegative的基础上区分正数和0.考虑运算 (!x)的结果。x位0时值为1,非零时值为0。那么 (!(!x))即!!x,运算在x为0时值为0,非零时值为1。这样就能区分0和正数了。也就是 “(负数确定)+(非负数确定)&(0确定)” 。
int sign(int x) {
return (x >> 0x1F) | !!x;
}
(6)
-
byteXor - compare the nth byte of x and y, if it is same, return 0, if not, return 1
-
example: byteXor(0x12345678, 0x87654321, 1) = 1
-
byteXor(0x12345678, 0x87344321, 2) = 0
-
Legal ops: ! ~ & ^ | + << >>
-
Max ops: 20
-
Rating: 2
思路:一个字节相当于8个二进制位,通过右移操作并将结果与0xff即255进行与运算,即可取得这一字节的值。异或的特性是若两个数相等,则异或结果为0,利用这一特性即可得出答案。
int byteXor(int x, int y, int n) {
int temp = ((x ^ y) >> (n << 3)) & 0xFF;
return !!temp;
}
(7)
- fitsBits - return 1 if x can be represented as an
- n-bit, two’s complement integer.
- 1 <= n <= 32
- Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 15
- Rating: 2
思路:shift=32-n。即先左移32-n位,在右移32-n位,即保留最后n位数。在与x异或,若两者相同表示x可被表示为一个n位整数,! 0为1。
int fitsBits(int x, int n) {
int shift = (~n+1)+32;
return !(x^((x<<shift)>>shift));
}
(8)
- isEqual - return 1 if x == y, and 0 otherwise
- Examples: isEqual(5,5) = 1, isEqual(4,5) = 0
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 5
- Rating: 2
思路:异或即可。具体:x和y相等那么(x^y)为0!为1即same,return 1;x和y不等那么(x^y)非0!为0 即if not,return 0。
int isEqual(int x, int y) {
return !(x^y);
}
(9)
- logicalShift - shift x to the right by n, using a logical shift
- Can assume that 0 <= n <= 31
- Examples: logicalShift(0x87654321,4) = 0x08765432
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 20
- Rating: 3
思路:逻辑右移和算数右移在数为非负数的情况下是等价的。先考虑负数的情况。因为算数右移在负数情况下会将高位置1,先将符号位提出,移位后再将符号位补回,但操作后符号位可能失去原来的性质,要注意这一点的处理。
int logicalShift(int x, int n) {
int offset = 0x1 << 31;
int offsetValue = ~(offset >> n << 1);
return (x >> n) & offsetValue;
}
(10)
- rempwr2 - Compute x%(2^n), for 0 <= n <= 30
- Negative arguments should yield negative remainders
- Examples: rempwr2(15,2) = 3, rempwr2(-35,3) = -3
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 20
- Rating: 3
思路:取模操作的实现:对于x<0来说:先用p算出除数的相反数,再用ans表示除数+余数,最后返回除数的相反数+除数+余数即可。对于x>=0来说:先用p算出除数的相反数,ans为x除以2^n的余数,最后返回ans即可。
int rempwr2(int x, int n) {
int p = (~0) << n;
int ans = x & (~p);
return ans + ( ( ( x & (~ans + 1) ) >> 0x1F ) & p );
}
(11)
- isLess - if x < y then return 1, else return 0
- Example: isLess(4,5) = 1.
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 24
- Rating: 3
思路:分两种情况: ①异号时,符号位为正的大。②同号时,两数相减,然后比较。可以避免计算溢出。
int isLess(int x, int y) {
int not_y = ~y;
return ( ( ( ( x + not_y + 1 ) & ( x ^ not_y ) ) | ( x & not_y ) )>> 0x1F ) & 1;
}
(12)
- bitMask - Generate a mask consisting of all 1’s
- lowbit and highbit
- Examples: bitMask(5,3) = 0x38
- Assume 0 <= lowbit <= 31, and 0 <= highbit <= 31
- If lowbit > highbit, then mask should be all 0’s
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 16
- Rating: 3
思路:注意lowbit大于highbit的特判,利用异或特性。具体:当lowbit>highbit,& (i << lowbit)会直接覆盖得出的错误的数并置为0,((i << highbit) << 1) ^ (i << lowbit)中 (i << highbit) << 1为确定高位的数要取到 highbit+1才能保证在^运算中保留highbit ,低位也是如此,但不需要lowbit-1 ,进行^运算后即保留highbit到 lowbit为1,返回即可。
int bitMask(int highbit, int lowbit) {
int i=~0;
return (((i << highbit) << 1) ^ (i << lowbit)) & (i << lowbit);
}
(13)
- 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) {
return 2;
}
(14)
- 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 和(-X)进行与运算。两相反数(非0)取反的&运算结果永远为0,0右移31位为0,0&1为0。0与0取反的&运算永远为-1,-1右移31位为-1,-1&1为1,显然:当且仅当X=0是结果的符号位为0。
int logicalNeg(int x) {
return((~(~x+1)&~x)>>31)&1;
}
(15)
- isPower2 - returns 1 if x is a power of 2, and 0 otherwise
- Examples: isPower2(5) = 0, isPower2(8) = 1, isPower2(0) = 0
- Note that no negative number is a power of 2.
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 20
- Rating: 4
思路:2^k必定大于0,首先排除负数和0的情况。运用lowbit位操作的方法计算 x&(-x)其结果为X的最低为1的位。如果结果正好等于X,则符合题意。
int isPower2(int x) {
return !(((x&(~x+1))^x)|(!x)|(x>>31));
}
(16)
- parityCheck - returns 1 if x contains an odd number of 1’s
- Examples: parityCheck(5) = 0, parityCheck(7) = 1
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 20
- Rating: 4
思路:5步相互独立,每一步都为了寻找到能够消去1的移位,虽然有几步会增加1的数量,但1是对称,所以找到合适的移位数就可以一次性全部消去。因为1是偶数个x最终为0 ,并且要找偶数个1所以取32的一半,再一半……直到1为止。
int parityCheck(int x) {
x = x ^ (x >> 16);
x = x ^ (x >> 8);
x = x ^ (x >> 4);
x = x ^ (x >> 2);
x = x ^ (x >> 1);
return x & 0x1;
}
(17)
- trueThreeFourths - multiplies by 3/4 rounding toward 0,
- avoiding errors due to overflow
- Examples: trueThreeFourths(11) = 8
-
trueThreeFourths(-9) = -6
-
trueThreeFourths(1073741824) = 805306368 (no overflow)
- Legal ops: ! ~ & ^ | + << >>
- Max ops: 20
- Rating: 4
思路:首先通过右移一位和右移两位两个操作求得整数部分。然后判断小数部分以及是否是负数。
int trueThreeFourths(int x) {
int y=x&0x3;
x=x>>2;
return (x<<1)+x+((y+y+y+((x>>0x1F)&0x3))>>2);
}
2.测试结果截图
五、实验总结
通过这次试验,我得知自己对位的相关操作的理解还不太到位,需要勤学多练,加深理解;部分函数理解不透彻,不能完整实现函数功能,可通过与他人交流、查阅资料得到处理。平时也可以通过自行进行习题演练,增强函数实现和优化方面的技能。除此之外,我更加深刻地了解数据与程序的机器级表示和处理,并加深了解数据类型的转换规则,能够在虚拟机的环境中通过两大测试优化函数功能,实现一些基础运算工程的功能。并且加深了和他人的交流,进一步提升了自学能力。