CSAPP第二章实验datalab解答

第1题 用按位与和取反实现按位异或

要求如下:

bitXor - x^y using only ~ and & 
Example: bitXor(4, 5) = 1
Legal ops: ~ &
Max ops: 14
Rating: 1

如果学过数电或者是数理逻辑的话,这题应该不难,如果是数电的题目,实际上就是让你用与门和非门来实现异或。对于数理逻辑而言,也就是用与和非来实现异或,我们知道,异或就是不同则为1,相同则为0,对于单独的一位而言,就是1和0或者0和1这两种组合可以异或得到1,而对于位向量而言,也就是x&~y或者~x&y。这里需要一个或操作,但是并不允许我们使用,那么思路就是用与和非来实现或,在离散数学中我们知道,与和非这两个联结词的集合是极小全功能的,等价于与或非这三个联结词的集合,这是因为或是可以用与和非表示的,也就是x|y = ~(~x&~y),这里的证明可以使用 De Morgan’s laws 。于是只需要把这里的x和y替换成上面的两个就行了。

代码如下:

int bitXor(int x, int y) {
	/* 
	Since "x bitXor y" equals "(x & ~y) | (~x & y)",
	we just need to implement "|" with just "&" and "~".
	And "x | y" equals "~(~x & ~y)".
	*/
	int x_and_noty = x & ~y;
	int notx_and_y = ~x & y;
	int not_x_and_noty = ~x_and_noty;
	int not_notx_and_y = ~notx_and_y;
	int x_bitXor_y = ~(not_x_and_noty & not_notx_and_y);
	return x_bitXor_y;
}

第2题 返回补码中的最小值Tmin

要求如下:

tmin - return minimum two's complement integer 
Legal ops: ! ~ & ^ | + << >>
Max ops: 4
Rating: 1

这题并不难,因为 T m i n Tmin Tmin 实际上就是100..0,一个1后面跟着31个0(因为int是32位的)。于是只需要将00..1,也就是十进制数值的+1,左移31位,就可以得到了。

代码如下:

int tmin(void) {
	/*
	The bit expression of Tmin is 100..00, with one '1' followed by thirty-one '0'.
	So we just need to shift 000..01 left 31 positions,
	so that the '1' will be at the leftmost position, namely, Tmin.
	*/
  	int one = 1;
  	return one << 31;
}

第3题 判断是否为Tmax(0x7fffffff)

要求如下:

isTmax - returns 1 if x is the maximum, two's complement number,and 0 otherwise 
Legal ops: ! ~ & ^ | +
Max ops: 10
Rating: 2

虽然看上去还挺简单的,但是由于受的限制比较多,只允许用位运算和加法,所以难度系数就提高了,作者一开始没有看清题目,然后用了移位操作,写完之后运行检测程序才发现这一点。

先来分析一下Tmax有什么特别的地方,那么就会发现,如果你给它加上个1会如何呢,本来是0后面全是1,然后就变成了1后面全是0,这时候如果把+1前和+1后异或一下,那么就变成了全为1。对于别的数而言有这样的特点么,那就只有-1有这个特点了,因为-1的位表示是全1,那么+1之后就变成了全0,除此之外还有么?应该是没有了。

不妨直观上思考一下,为什么只有2个数有这样的特点。分2种情况考虑——最低位为0和最低位为1。如果最低位为0,那么+1之后再异或必然得到1,毕竟其他位都不变,只变了1位;如果最低位为1,那么+1之后就会进行进位,如果不是上面说的2个数,那么必然会到某一位就进位停止了,而剩下的高位不变,于是必然高位会为0。

所以可以利用这样的特点解决这道题,于是我们只需要从2种情况中区分出Tmax了,对于-1而言,+1之后就会变为0,所以我们依旧可以利用+1后的结果,对这个结果取一个非,对于C语言,非0即1,所以用!作用在+1后的结果,如果为1,也就不是我们想要的(因为本来是+1后取个非如果为1,说明+1后为0,则原来是-1),如果为0,就是了。最后,我们把这个取非的结果和之前的判断结果做异或操作,这样,我们就得到了一种解法。

代码如下:

int isTmax(int x) {
	int xPlusOne = x + 1;
	int notTmaxOrMinusOne = !(~(x ^ xPlusOne));
	return notTmaxOrMinusOne ^ !xPlusOne;
}

总共用了6个操作符,算是中规中矩的一种做法了,说实话看上去还存在挺多冗余的,只做为参考,并非最优解(全部做完之后会去看看最优解怎么做的,然后补充到这里)。

第4题 判断奇数位是否都是1(偶数位不管)

要求如下:

allOddBits - return 1 if all odd-numbered bits in word set to 1
Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 12
Rating: 2

不是说只有全是a才返回1,偶数位可以为1

有个比较简单的思路,就是使用掩码,这里可以这么解决是因为掩码全是A,而且可以使用移位操作,那么就可以通过0xAA进行扩展,变成全为A(8个A),如下:

0xAA
0xAAAA
0xAAAAAAAA

如果用0xAAAAAAAA作为掩码做与操作,如果结果为0xAAAAAAAA,也就是说原来的奇数位都为1。于是我们只需要判断是否结果为0xAAAAAAAA,只需要将结果和掩码做个异或,如果得到0,也就说明结果就是0xAAAAAAAA

代码如下:

int allOddBits(int x) {
	/*
	if x and 0xAAAAAAAA equals 0xAAAAAAAA,
	then all bits are odd. 
	*/
  	int twoA = 0xAA;
  	int fourA = twoA + (twoA << 8);
  	int eightA = fourA + (fourA << 16);
  	return !((eightA & x) ^ eightA);
}	

第5题 用位操作实现相反数

要求如下:

negate - return -x 
Example: negate(1) = -1.
Legal ops: ! ~ & ^ | + << >>
Max ops: 5
Rating: 2

这题如果知道补码如何得到相反数就十分简单了,如果不知道这个规律还是比较难的。对于补码而言,如果要从x得到-x,需要按位取反然后+1即可。

代码如下:

int negate(int x) {
  	return ~x + 1;
}
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值