深入理解计算机系统 第2章 习题解析 Part2
这次更新几题,参考了如下资料:
https://github.com/mofaph/csapp/tree/master/exercise
Chapter 2
66
参考了如下资料:
https://github.com/mofaph/csapp/blob/master/exercise/ex2-66.c
重点是如下操作:
x = x | (x >> 1)
这个操作可以逐步将x化成[0…011…1]的形式,代码如下:
/*
* Generate mask indicating' leftmost 1 in x. Assume w=32.
* For example OxFFOO -> 0x8000, and 0x6600 --> 0x4000.
* If x = 0, then return 0.
*/
#include <stdio.h>
int leftmost_one(unsigned x){
//第i次增加2^(i-1)个1,化成0...01...1
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
//化成0...010...0
x = (x + 1) >> 1;
return x;
}
int find_left_most(unsigned x){
if (x == 0){
return 0;
}
int d = 0;
while (x != 0){
d++;
x = x >> 1;
}
int res = 1 << (d - 1);
return res;
}
void test(){
int start = 0;
int end = 1000;
for (unsigned i = start; i <= end; i++){
int d1 = find_left_most(i);
int d2 = leftmost_one(i);
if (d1 != d2){
printf("Wrong answer for %d!\n", i);
break;
}
}
}
int main(){
printf("%d\n", sizeof(int));
test();
return 0;
}
67
主要是如下原因:
If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
解决方法是使用了如下性质:
所以得到了如下代码:
#include <stdio.h>
/* The following code does not run properly on some machines */
int bad_int_size_is_32() {
/* Set most significant bit (msb) of 32-bit machine */
int set_msb = 1 << 31;
/* Shift past msb of 32-bit word */
int beyond_msb = 1 << 32;
/* set_msb is nonzero when word size >= 32
beyond_msb is zero when word size <= 32 */
return set_msb && !beyond_msb;
}
int int_size_is_32() {
int x = 0x8000000;
return !(!x);
}
int int_size_is_64() {
int x = 0x80000000000000;
return !(!x);
}
void test(){
int d1 = int_size_is_32();
int d2 = int_size_is_64();
int d = sizeof(int);
if (d1 && (d == 4)){
printf("int size if 32\n");
}else if (d2 && (d == 64)) {
printf("int size if 8\n");
}else{
printf("wrong answer\n");
}
}
int main(){
test();
return 0;
}
68
比较常规,主要是要对$n=w$的情形进行特殊处理:
/*
* Make with least signficant n bits set to 1
* Examples: n=6 --> 0x3f, n=17 --> 0x1FFFF
* Assume 1 <= n <= w
*/
#include <stdio.h>
int lower_bits(int x, int n){
int w = sizeof(int) << 3;
//判断n是否等于w,相等时为1,否则为0
int m1 = !(w ^ n);
//n等于w时为1111,否则为0000
m1 = ~m1 + 1;
//n=w时的mask
int m2 = (~0);
//其余情形mask
int m3 = (1 << n) - 1;
//生成结果
int r1 = (x | m2);
int r2 = (x | m3);
int r = (r1 & m1) | (r2 & (~m1));
return r;
}
int test_helper(int x, int y, int n){
if (n == 32){
return y == -1;
}
int flag = 1;
unsigned x1 = x;
unsigned y1 = y;
//检查末n位
for (int i = 0; i < n; i++){
int d = y % 2;
x = x >> 1;
y = y >> 1;
if (d == 0){
flag = 0;
break;
}
}
//判断剩余部分是否相等
if (x != y){
flag = 0;
};
return flag;
}
void test(){
int start = -10000;
int end = 10000;
int N = sizeof(int) * 8;
int f = 1;
for (int n = 0; n <= N; n++){
if (!f){
break;
}
for (int i = start; i <= end; i++){
int j = lower_bits(i, n);
int flag = test_helper(i, j, n);
if (!flag){
printf("Wrong answer for i = %d, n = %d\n", i, n);
printf("i = %x\n", i);
printf("j = %x\n", j);
f = 0;
break;
}
}
}
if (f){
printf("Pass test!\n");
}
}
int main(){
test();
return 0;
}
69
/*
* Do rotating left shift.Assume 0 <=n <w
* Examples when x = Ox12345678 and w = 32:
* n=4 -> Ox23456781, n=20 -> Ox67812345
*/
#include <stdio.h>
unsigned rotateleft(unsigned x, int n){
int w = sizeof(int) << 3;
unsigned y = (x << n) | (x >> (w - n));
return y;
}
void get_bit(unsigned x, int* arr){
int w = sizeof(int) << 3;
for (int i = 1; i <= w; i++){
arr[w - i] = x % 2;
x = x >> 1;
}
}
int test_helper(int x, int y, int n){
int w = sizeof(int) << 3;
int x1[w];
int y1[w];
get_bit(x, x1);
get_bit(y, y1);
//比较
for (int i = w - 1; i >= 0; i--){
int j = (i - n + w) % w;
if (x1[i] != y1[j]){
return 0;
}
}
return 1;
}
void test(){
int start = 0;
int end = 10000;
int N = sizeof(int) * 8;
int f = 1;
for (int n = 0; n < N; n++){
if (!f){
break;
}
for (unsigned i = start; i <= end; i++){
unsigned j = rotateleft(i, n);
if (!test_helper(i, j, n)){
printf("Wrong answer for i = %d, n = %d\n", i, n);
f = 0;
break;
}
}
}
if (f){
printf("Pass test!\n");
}
}
int main(){
test();
return 0;
}
70
求出n位的表示范围,然后判断x是否属于即可:
/*
* Return 1 when x can be represented as an n-bit,2's-complement
* number; 0 otherwise
* Assume 1 <= n <= w
*/
#include <stdio.h>
int fits_bits(int x, int n){
int w = sizeof(int) << 3;
//n=w时为1,否则为0
int f = !(n ^ w);
//上下限
int min_num = - (1 << (n - 1));
int max_num = (1 << (n - 1)) - 1;
//求差
int x1 = x - min_num;
int x2 = max_num - x;
//x1>=0时f1=1,否则为1
int f1 = !(x1 >> (w - 1));
//x2>=0时f2=1,否则为1
int f2 = !(x2 >> (w - 1));
//生成结果
int res = f | (f1 && f2);
return res;
}
int fits_bits_(int x, int n){
int w = sizeof(int) << 3;
if (n == 32){
return 1;
}
int min_num = - (1 << (n - 1));
int max_num = (1 << (n - 1)) - 1;
if (x >= min_num && x <= max_num){
return 1;
}
return 0;
}
void test(){
int start = -10000;
int end = 10000;
int N = sizeof(int) * 8;
int f = 1;
for (int n = 1; n <= N; n++){
if (!f){
break;
}
for (int i = start; i <= end; i++){
if (fits_bits(i, n) != fits_bits_(i, n)){
printf("Wrong answer for i = %d, n = %d\n", i, n);
f = 0;
break;
}
}
}
if (f){
printf("Pass test!\n");
}
}
int main(){
test();
return 0;
}
71
该函数的作用是返回word的第bytenum字节的元素,注意该元素可能为负。
现在看原始代码:
int xbyte(packed_t word, int bytenum){
return (word >> (bytenum << 3) & 0xFF;
}
该代码不会处理元素为负的情形,正确代码如下(利用了算数右移的性质):
int xbyte(packed_t word, int bytenum){
int d = 24 - (bytenum << 3);
int res = (word << d) >> 24;
}
参考资料:
https://github.com/mofaph/csapp/blob/master/exercise/ex2-71.c
总结
66题比较难,71的技巧比较有意思,可以多回顾几遍。
技巧1
x = x | (x >> 1)
这个操作可以逐步将x化成[0…011…1]的形式。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere