一、实验内容(实验步骤或者程序编写)
1、安装32位linux虚拟机
2、按照要求补充完bits.c里面的代码
实验前请认真阅读本文档和bits.c中的代码及注释(特别是bits.c前面部分的编程说明与示例),然后根据要求相应完成bits.c中的各目标函数的实现代码。 实验中实现的函数代码必须满足下述基本条件:
只能使用有限类型和数量的C语言算术、逻辑操作,具体要求见每个函数前的注释说明中的"Legal ops"(允许使用的操作符)和"Max ops"(允许使用的最多操作符数量)。
不得使用任何形式的强制类型转换。
不得使用除整型外的任何其它数据类型,如数组、结构、联合等。
不得定义和使用宏。
不得定义除已给定的框架函数外的其他函数,不得调用任何函数。
除上述一般性要求外,非浮点数函数还必须满足下列要求:
只能使用顺序程序结构(即不得使用if、do、while、for、switch等循环或条件分支控制程序结构。
不得使用超过8位表示的常量(即其值必须位于[0,255]中)。
浮点数函数还必须满足下列要求:
可以使用循环和条件控制;
可以使用整型和无符号整型常量及变量(取值不受[0,255]限制);
不得使用任何浮点数据类型、操作及常量。
上述实验要求的主要目的是使得你必须从二进制位的角度考虑数据,进而更清楚地理解数据的二进制表示。
3、安要求检查代码正确性
使用dlc检查函数实现代码是否符合实验要求中的编码规则
完成bits.c后,调用如下命令进行检查:
$ ./dlc bits.c
dlc将返回错误信息如果它发现了错误,例如不允许使用的操作符、过多数量的操作符或者非顺序的代码结构。如果程序代码满足规则要求,dlc将不输出任何提示。 使用-e选项调用dlc
$ ./dlc -e bits.c
可使dlc打印出每个函数使用的操作符数量。 输入" ./dlc -help"可打印出dlc的可用命令行选项列表。
使用btest检查函数实现代码的功能正确性
首先使用如下命令编译生成btest可执行程序:
$ make
如下调用btest命令检查bits.c中所有函数的功能正确性:
$ ./btest
注意每次修改bits.c后都必须使用make命令重新编译生成btest程序。 为方便依次检查测试每一函数的正确性,可如下在命令行使用"-f"选项跟上函数名,以要求btest只测试所指定的函数:
$ ./btest -f bitXor
进一步可如下使用"-1, -2, -3"等选项在函数名后输入特定的函数参数:
$ ./btest -f bitXor -1 7 -2 0xf
(README文件中有关于btest程序的使用说明)
二、实验结果及分析(这部分重点写)
1、作业代码(注释中有每道题的解题思路)
#if 0
#endif
int lsbZero(int x) {
return (x>>1)<<1; //左移会在低位补零
}
int byteNot(int x, int n) {
int a = 0xff;
n<<=3;
a<<=n; //取出目标字节
x^=a; //取反
return x;
}
int byteXor(int x, int y, int n) {
int a = 0xff;
int b;
int result;
n <<= 3;
x >>= n , y >>= n;
x &= a , y &= a; //取到x和y的第n字节
b = x^y; //判断是否相等
result = !!b; //映射到0和1
return result;
}
int logicalAnd(int x, int y) {
int a;
x = !!x;
y = !!y; //映射到0和1
a=x&y;
return a;
}
int logicalOr(int x, int y) {
int a;
x = !!x;
y = !!y; //映射到0和1
a=x|y;
return a;
}
int rotateLeft(int x, int n) {
int h=x<<n;
int l=x >> ((n^31)+ 1); //右移相应位数,其中(n^31)+ 1是求n在mod 32下的补码,相当于32-n;
l &= ~((~0)<<n); //高位有可能都是1,将高位变为0
return l|h;
}
int parityCheck(int x) {
x ^=(x>>16); //暴力去做的话,花费肯定会大于20个运算符。用分治的思想,运算次数减少为log(N)
x ^= (x >> 8); //一个长为n的数,只考虑 k和k+n/2这两个数中1的个数是不是偶数 (k=1、2、3...n/2),是偶数记为0,由x ^=( x>> (n/2))实现
x ^= (x >> 4); //有性质:偶+偶=偶,偶+奇=奇,奇+奇=偶 对应着 0^0=0 0^1=1 1^1=0 ,可以证明算法正确性
x ^= (x >> 2);
x ^= (x >> 1);
x &= 0x1; // 最后考虑末尾是1还是0即可达到目的。
return x;
}
int mul2OK(int x) {
int h1 = (x>>31)&0x1;
int h2 = ((x<<1)>>31)&0x1; //取出最高位和次高位
int ans = (~(h1 ^ h2)) & 0x1; //判断是否相等
return ans;
}
int mult3div2(int x) {
int a=x+x+x;
int h1=(a>>31)&0x1; //如果是正数,则加0,否则加1
return (a+h1)>>1;
}
int subOK(int x, int y) {
int res = x+(~y)+1; //相当于求出加法器的OF位
int a = ((res^x)&(x^y))>>31; //如果两个加数的符号位相同,而与它们的和的符号位不同,则发生溢出
return !a;
}
int absVal(int x) {
int a = ((x>>31)&0x1) + ~0; //如果是正数 a=0xffffffff,如果是负数 a=0x00000000
x = (~a&(~x+1))|(a&x); //如果是正数则不做处理,否则取反码加1转化为原码,将符号位变为0
return x;
}
unsigned float_abs(unsigned uf) {
unsigned res=uf&0x7fffffff; //取绝对值
if(res>0x7F800000){ //判断是否为NaN
return uf;
}else{
return res;
}
}
int float_f2i(unsigned uf) {
int fh = (uf>>31)&1; //取符号位
int jm = ((uf>>23)&0xff) - 0x7f; //取阶码,并做预处理(-127),得到解码表示的数字的原码
int ws = (uf&0x7fffff) | (1<<23); //取位数,并补上最高位的1
if(jm<0) return 0; //绝对值小于,返回0
if(jm>=31) return 0x80000000u; //超出int表示范围,返回0x80000000u
if(jm==0x80) return 0x80000000u; //是NaN或无穷,返回0x80000000u
if(jm<23){ //处理w尾数
ws >>= (23-jm);
}else{
ws <<= (jm-23);
}
if(fh){ //处理符号
return -ws;
}else{
return ws;
}
}
2、进行语法检查,编译,正确性检查
三、实验心得
最开始做mul2OK这道题的时候,明明代码没有问题,在助教老师的电脑上也能通过,但在我的电脑上就无法通过测试。后来猜测是因为我装的linux系统是64位的原因,于是重新安装了一个32位的linux,问题就解决了。