天天看點

深入了解計算機系統 作業1 2.61 2.65 2.73 2.76解答

2.61

A !(~x)

B !x

C !(~ (x | 0x00ffffff))

D !(~ (x | 0xffffff00))

2.65

分析:因為本題受12次操作的限制,故不能按位計算是否該位為1。考慮到本題隻需要判斷1的個數的奇偶性,而并不需要計算一共有多少個1。那麼我們考慮到如果能去掉偶數個1對結果并不會産生影響,這需要快速的去掉偶數個1。因為異或運算恰好可以把同為1時變成0。然後在利用分治的方法,整體異或來減少操作次數。

操作:1

1.前16和後16位對齊後異或,那麼這時候原來32位的奇偶性和目前異或出來的16位的結果一緻。

2.同理前8位和後8位對齊異或。

3.同理前4位和後4位對齊異或。

4.同理前2位和後2位對齊異或。

5.同理前1位和後1位對齊異或。

最後隻需要判斷最後那一位上是1還是0即可。

int even_ones(unsigned x)
{
	unsigned  y = x >> 16; x ^= y;
	y = x >> 8; x ^= y;
	y = x >> 4; x ^= y;
	y = x >> 2; x ^= y; 
	y = x >> 1; x ^= y; 

	return !(x & 1);
	
}      

2.73

【分析】首先判斷是否有無溢出,因為不能用判斷符号(<,>),是以我們可以考慮符号位,如果(x+y)的符号位和x與y的符号位都不同,則發生溢出。這個可以用兩次異或和一次與操作完成。

令ans= x+y

令ALL= (( x ^ ans) & (y ^ ans)) >> ( intBitCnt - 1);顯然當算術溢出時,ALL的32個位上的值均為1(111.....111),否則ALL= 0;Ps:因為是算術右移。

然後繼續判斷是正溢出還是負溢出,隻需要看x或者y的符号位即可判斷。

令x_sign= x >> (intBitCnt – 1); 如果正溢出則x_sign= 0 否則各個數位上的值均為1(111....111)。

對于傳回的結果,ans| ALL 之後,如果溢出則結果為全1,否則結果仍為x+y。如果正溢出我們隻需要令其減去(1<<(intBitCnt – 1))即可,如果負溢出令其減去(1<<(intBitCnt-1)) ^ 111....111(全部1)即可,則否減去0。

這樣隻要上面參與運算的1與是否溢出,是否正負溢出有關就可以了。

ALL& 1 = 1 是溢出的判斷條件。

x_sign& ALL = 111.....111(全1)是負溢出的條件,0則可能正溢出,也可能不溢出。

int saturating_add(int x,int y)
{
	int intBitCnt = sizeof(int) << 3;
	int ans = x + y;
	int ALL = (( x ^ ans) & (y ^ ans)) >> ( intBitCnt - 1);
	int x_sign = x >> ( intBitCnt  - 1);
	return (ans | ALL) - ( (ALL & 1) << ( intBitCnt - 1))^ (x_sign & ALL);
}      

2.76

AK = 5 【code】x<<2+x

Bk = 9 【code】x<<3+x

Ck = 30【code】x<<5-x<<1

Dk = -56 【code】x<<3- x << 6