实验简介
Data LAB 目的是熟悉位运算
要求:
- 只修改
bit.c
- 使用
btest
进行验证 - 每次修改完之后都要
make clean
再make
- 整数部分:要求只能使用规定的操作符并且不能使用循环、条件语句
- 在函数开始时声明所有变量,只能使用局部变量
- 不能使用其他函数/宏/int外的类型/类型转换
int
都是默认二进制补码编码 2’s complement,32bit- 要考虑数据溢出的情况,比如相减,同号才能相减,否则结果出错
Tips:
# ./btest -f [函数名]
,检验某个函数./btest
检验所有函数- 关注
int
型的表示范围 -2^31~2^31-1以及一些特殊的数字的补码编码-2^31:0x80 00 00 00
-1:0xff ff ff ff
- 一个数的相反数是
~x+1
- 在float的实验中要对该数是不是规格化分情况
- 逻辑右移不带符号,
>>
是算术右移,带符号 - 0的特性,若x=0, ~x+1和x的符号位都为0。而其他情况则至少有一个数符号位为1。(也可能两个符号位都为1的情况,如x=0x80 00 00 00
个人认为最难的是ilog2
文件说明
Github地址:Data Lab
- bit.c:实现缓存模拟器的文件
- Examples:表示用例‘
- Legal ops:允许的操作符
- Max ops:最多操作数
- Rating:难度系数
在每一次更新之后,首先用make
生成文件,之后用相应的test
跑分即可
整形
logicalShift
/*
* 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
*/
int logicalShift(int x, int n) {
int val = ~(1<<31) ; // 0x7f ff ff ff
val = ((val >> n) <<1)+1;
return val & (x>>n);
}
逻辑右移:需要去掉负数带来的符号位。产生一个数,前n-1位0,之后全为1,和算数右移后的数进行按位与操作,使左边n-1位为0。
bitCount
/*
* bitCount - returns count of number of 1's in word
* Examples: bitCount(5) = 2, bitCount(7) = 3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 40
* Rating: 4
*/
int bitCount(int x) {
int mask = ((0x01<<8|0x01)<<8|0x01)<<8|0x01 ;
int val = mask & x;
val += mask & x>>1;
val += mask & x>>2;
val += mask & x>>3;
val += mask & x>>4;
val += mask & x>>5;
val += mask & x>>6;
val += mask & x>>7;
val += val>>16;
val += val>>8;
return val&0xff;
}
要求:计算32进制数x中1的个数
思路:如果依次检测,ops必然超过。可以每次检测4位,然后再进行累加。先初始化mask=0x01010101,用来检测x>>i的0,8,16,24位是否为1然后x顺序移动重复上述检测,一共8次。相当于将一个32位分成4段同时进行,结果存储在分别四段的8位中。整合:将前16位加到后16位上,然后把8~16位加到低8位。取最低8位为最后结果。
bang
/*
* bang - Compute !x without using !
* Examples: bang(3) = 0, bang(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int bang(int x) {
return ((~((~x+1)^x))>>3