实验环境搭建
参考以下链接
https://zhuanlan.zhihu.com/p/505497911
实验内容
介绍
The purpose of this assignment is to become more familiar with bit-level representations of common patterns, integers, and floating-point numbers. You’ll do this by solving a series of programming “puzzles.”
此任务的目的是更熟悉常见模式、整数和浮点数的位级表示。您将通过解决一系列编程“难题”来实现这一点
我们仅仅需要完成bit.c中的相关函数
每次编写新的代码后重新make
./btest -f 实现的函数
以bitXor为例子
要实现的函数
- bitXor
只利用取反和&实现异或操作
异或的德摩根律是
(x&~y+ ~x&y)
考虑到只能用非和与,所以对上式取反
int bitXor(int x, int y) {
return ~(~(x&(~y))&(~(y&(~x))));
}
测试结果
- tmin
返回最小补码
以8bit的数字为例,可以表示的范围是-128-127
127考虑符号位是0111 1111
-128=-1+ -127
转换成补码形式的运算可以得到是1000 0000
因为在补码里面负数的符号位既是符号位也是数值位置
所以32位机器下最小的补码是1左移31位
int tmin(void) {
return 1<<31;
}
- isTmax
返回最大补码
最大的补即为0x7fffffff
int isTmax(int x) {
if(x|0x7FFFFFFF==0)
return 1;
else return 0;
}
- allOddBits
判断数值的奇数位是否全是1
0xAA=1010 1010刚好奇数位置都是1
int allOddBits(int x) {
int a=0xAAAAAAAA;
x=x&a;
x=x^a;
return !x;
}
- negate
返回输入值的负数
int negate(int x) {
return (~x+1);
}
- isAsciiDigit
判断ASCII编码是否在0-9之间
代码如下
int isAsciiDigit(int x) {
int a;
a=x-0x30;
a=a>>31;
int b=0x39-x;
b=b>>31;
return !a&!b;
}
将负数转换补码形式即可
int isAsciiDigit(int x) {
int a;
a=x+(~0x30+1);
a=a>>31;
int b=0x39+(~x+1);
b=b>>31;
return !a&!b;
}
取符号位进行比较,是否大于0x30和小于0x39
- conditional
条件运算符,x?y:z
x=0 ? yes->z
else y;
不是
区别于
if(x) y;
else z;
错误示例
int conditional(int x, int y, int z) {
x=(x>>31)&0x1;//这里取符号位作为判断条件
return ((~x+1)&z)|(~(~x+1)&y);
}
正确打开方式
int conditional(int x, int y, int z) {
x=!!x;
return ((~x+1)&y)|(~(~x+1)&z);
}
在CSAPP书中
当x是0时候,两次!运算得到的结果是0,0按位取反+1是-0,还是0,全部翻转然后&z,即可得出z。
这里这道题困扰了我很久,因为没有清楚知道三元运算符的实际意义。
- isLessOrEqual
最直接的做法就是这种
但是这种做法存在的问题也很明显就在边界值
存在溢出问题。
正确打开方式
int isLessOrEqual(int x, int y) {
int z = (y + ~x + 1) >> 31;
int a = x >> 31;
int b = y >> 31;
int xor1 = a ^ b;
int result = (~xor1 & z) | (xor1 & b);
return !result;
}
这里借鉴了别人的做法
取x,y的符号位,如果符号相同就不会存在溢出的问题
如果符号不同,取y的符号位,负数减去正数肯定还是负数,正数减去负数肯定还是正数。
- logicalNeg
要求:实现!的功能
int logicalNeg(int x) {
x|=x>>16;
x|=x>>8;
x|=x>>4;
x|=x>>2;
x|=x>>1;
return (~x)&0x1;
}
思路:将所有位进行或运算