初始完成日期:2017.9.26

许可:除2.55对应代码外(如需使用请联系 randy.bryant@cs.cmu.edu),任何人可以自由的使用,修改,分发本文档的代码。

本机环境: (有一些需要在多种机器上测试的就没有试验)

frank@under:~/tmp$ uname -a
Linux under 4.10.0-35-generic #39~16.04.1-Ubuntu SMP Wed Sep 13 09:02:42 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

2.55

/*这一段代码的大部分来自http://csapp.cs.cmu.edu/3e/students.html*/
/* $begin show-bytes */
#include <stdio.h>
/* $end show-bytes */
#include <stdlib.h>
#include <string.h>
/* $begin show-bytes */typedef unsigned char *byte_pointer;void show_bytes(byte_pointer start, size_t len) {size_t i;for (i = 0; i < len; i++)printf(" %.2x", start[i]);    //line:data:show_bytes_printfprintf("\n");
}void show_int(int x) {show_bytes((byte_pointer) &x, sizeof(int)); //line:data:show_bytes_amp1
}void show_float(float x) {show_bytes((byte_pointer) &x, sizeof(float)); //line:data:show_bytes_amp2
}void show_pointer(void *x) {show_bytes((byte_pointer) &x, sizeof(void *)); //line:data:show_bytes_amp3
}
/* $end show-bytes *//* $begin test-show-bytes */
void test_show_bytes(int val) {int ival = val;float fval = (float) ival;int *pval = &ival;show_int(ival);show_float(fval);show_pointer(pval);
}
/* $end test-show-bytes */void simple_show_a() {
/* $begin simple-show-a */
int val = 0x87654321;
byte_pointer valp = (byte_pointer) &val;
show_bytes(valp, 1); /* A. */
show_bytes(valp, 2); /* B. */
show_bytes(valp, 3); /* C. */
/* $end simple-show-a */
}void simple_show_b() {
/* $begin simple-show-b */
int val = 0x12345678;
byte_pointer valp = (byte_pointer) &val;
show_bytes(valp, 1); /* A. */
show_bytes(valp, 2); /* B. */
show_bytes(valp, 3); /* C. */
/* $end simple-show-b */
}void float_eg() {int x = 3490593;float f = (float) x;printf("For x = %d\n", x);show_int(x);show_float(f);x = 3510593;f = (float) x;printf("For x = %d\n", x);show_int(x);show_float(f);}void string_ueg() {
/* $begin show-ustring */
const char *s = "ABCDEF";
show_bytes((byte_pointer) s, strlen(s));
/* $end show-ustring */
}void string_leg() {
/* $begin show-lstring */
const char *s = "abcdef";
show_bytes((byte_pointer) s, strlen(s));
/* $end show-lstring */
}void show_twocomp()
{
/* $begin show-twocomp */short x = 12345; short mx = -x; show_bytes((byte_pointer) &x, sizeof(short)); show_bytes((byte_pointer) &mx, sizeof(short));
/* $end show-twocomp */
}int main(int argc, char *argv[])
{int val = 12345;if (argc > 1) {if (argc > 1) {val = strtol(argv[1], NULL, 0);}printf("calling test_show_bytes\n");test_show_bytes(val);} else {printf("calling show_twocomp\n");show_twocomp();printf("Calling simple_show_a\n");simple_show_a();printf("Calling simple_show_b\n");simple_show_b();printf("Calling float_eg\n");float_eg();printf("Calling string_ueg\n");string_ueg();printf("Calling string_leg\n");string_leg();}return 0;
}

编译运行输出:

frank@under:~/tmp$ gcc 255.c && ./a.out
calling show_twocomp39 30c7 cf
Calling simple_show_a2121 4321 43 65
Calling simple_show_b7878 5678 56 34
Calling float_eg
For x = 349059321 43 35 0084 0c 55 4a
For x = 351059341 91 35 0004 45 56 4a
Calling string_ueg41 42 43 44 45 46
Calling string_leg61 62 63 64 65 66

数据的低位放置在低地址处,字符串按照顺序从低位地址排列。由此可知该机器为小端字节排序。


2.56

show-bytes代码同2.55

frank@under:~/tmp$ gcc 255.c && ./a.out 192837465
calling test_show_bytes59 77 7e 0b76 e7 37 4d28 00 4d 93 fc 7f 00 00

十进制192837465二进制表示为:1011011111100111011101011001。

  1. 十六进制表示为:0xB7E7759,所以第一行的数据表示这是小端字节排序。

  2. 将二进制小数点左移二十七位,由于单精度浮点数尾数部分只有23位(IEEE 756),多出来的4位1001将丢弃,由于默认的“round to even”,高位将进一位,即1.01101111110011101110110*2^27,bias = 2^7 - 1 = 127,所以阶码部分应为127+27=0x9A,整体为:0,10011010,01101111110011101110110即0x4D37E776。由此看出为小端字节排序。

  3. 该行为小端字节显示的指针。


2.57

#include <stdio.h>typedef unsigned char *byte_pointer;void show_short(void);
void show_long(void);
void show_double(void);
void show_bytes(byte_pointer start, size_t len);int main(int argc, char const *argv[])
{show_short();show_long();show_double();return 0;
}void show_bytes(byte_pointer start, size_t len) {size_t i;for (i = 0; i < len; i++)printf(" %.2x", start[i]);printf("\n");
}void show_short(void)
{short i = 12345;printf("short i = 12345\n");show_bytes((byte_pointer)&i, sizeof i);
}
void show_long(void)
{long i = 123456789;printf("long i = 123456789\n");show_bytes((byte_pointer)&i, sizeof i);
}
void show_double(void)
{double i = 123456789.0;printf("double i = 123456789.0\n");show_bytes((byte_pointer)&i, sizeof i);
}

编译运行输出:

frank@under:~/tmp$ ./a.out
short i = 1234539 30
long i = 12345678915 cd 5b 07 00 00 00 00
double i = 123456789.000 00 00 54 34 6f 9d 41

2.58

#include <stdio.h>
#include <stdint.h>int is_little_endian(void);int main(int argc, char const *argv[])
{return is_little_endian();
}int is_little_endian(void)
{int32_t i = 1;unsigned char *p = (unsigned char *)&i;if(*p){return 1;}return 0;
}

编译运行输出:

frank@under:~/tmp$ gcc 258.c && ./a.out ; echo $?
1

2.59

#include <stdio.h>int main(int argc, char const *argv[])
{int x = 0x89ABCDEF;int y = 0x76543210;printf("0x%.8X\n", x&0xFF | y&~0xFF);return 0;
}

编译运行输出:

frank@under:~/tmp$ gcc 259.c && ./a.out
0x765432EF

2.60

#include <stdio.h>unsigned replace_byte(unsigned x, int i, unsigned char b);int main(int argc, char const *argv[])
{printf("%#.8x\n", replace_byte(0x12345678, 2, 0xAB));printf("%#.8x\n", replace_byte(0x12345678, 0, 0xAB));return 0;
}unsigned replace_byte(unsigned x, int i, unsigned char b)
{int move = i * 8;return x & ~(0xFF << move) | b << move;
}

编译运行输出:

frank@under:~/tmp$ gcc 260.c && ./a.out
0x12ab5678
0x123456ab

2.61

#include <stdio.h>int main(int argc, char const *argv[])
{int x, y;   /* y means 0 should be returned */int sizeof_int = sizeof(int);/*condition A*/x = ~0;y = 0xFFFFFF00;printf("%d\t%d\n", !(~x), !(~y));/*condition B*/x = 0;y = 0x000000FF;printf("%d\t%d\n", !x, !y);/*condition C*/x = 0x000000FF;y = 0x0000000F;printf("%d\t%d\n", !((x ^ 0xFF)<<((sizeof_int-1)<<3)), !((y ^ 0xFF)<<((sizeof_int-1)<<3)));/*condition D*/x = 0x00FFFFFF;y = 0x0FFFFFFF;printf("%d\t%d\n", !(x >> ((sizeof_int-1) << 3)), !(y >> ((sizeof_int-1) << 3)));return 0;
}

编译运行输出:

frank@under:~/tmp$ gcc 261.c && ./a.out
1   0
1   0
1   0
1   0

2.62

#include <stdio.h>int int_shifts_are_arithmetic(void);
int int_shifts_are_logic(void);int main(int argc, char const *argv[])
{printf("%d\n", int_shifts_are_arithmetic());printf("%d\n", int_shifts_are_logic());return 0;
}int int_shifts_are_arithmetic(void)
{int x = ~0;return x >> 1 == x;
}int int_shifts_are_logic(void)
{unsigned x = ~0;return x >> 1 == x;
}

我这里由于没有不同字长/不同机器,就暂时用unsigned 代替了一下逻辑右移。

编译运行输出:

frank@under:~/tmp$ ./a.out
1
0

2.63

#include <stdio.h>unsigned srl(unsigned x, int k);
int sra(int x, int k); int main(int argc, char const *argv[])
{printf("%#.8x\n", srl(0x80000000, 8));printf("%#.8x\n", sra(0x80000000, 8));return 0;
}unsigned srl(unsigned x, int k)
{/* Perform shift arithmetically */unsigned xsra = (int) x >> k;/*思路是由k形成诸如0x00FFFFFF这样的掩码,与xsra进行与操作从而将高位置零*/unsigned w = sizeof(int) << 3;unsigned mask = ~(((1 << k)-1)<<(w-k)); /*(1 << k)-1能够获得低位连续为1,高位为0的掩码,但是其不能达到全1,于是继续向左移w-k然后取反*/return mask & xsra;
}int sra(int x, int k)
{/* Perform shift logically */int xsrl = (unsigned) x >> k;/*这个题目的关键点是判断符号位是否为1,通过test &= xsrl,test为零如果符号位为0,否则test不变(处于符号位位置*/unsigned w = sizeof(int) << 3;int test = 1 << (w-1-k);test &= xsrl;int mask = ~(test - 1);/*test为零时,~(test - 1)为全零,不会改变xsrl*/return mask | xsrl;
}

这个题目卡了一会,主要是不能用右移比较麻烦。

编译运行输出:

frank@under:~/tmp$ gcc 263.c && ./a.out
0x00800000
0xff800000

2.64

#include <stdio.h>int any_odd_one(unsigned x);int main(int argc, char const *argv[])
{printf("%d\t%d\n", any_odd_one(1011), any_odd_one(1024));return 0;
}int any_odd_one(unsigned x)
{unsigned sizeof_unsigned = sizeof(unsigned);unsigned w = sizeof_unsigned << 3;return !!(x << (w-1));
}

编译运行输出:

frank@under:~/tmp$ gcc 264.c && ./a.out
1   0

2.65 (终于碰见个四星的。。。)

/*二分法/加法无法达到要求
第一次尝试:
int odd_ones(unsigned x);int main(int argc, char const *argv[])
{int sizeof_int = sizeof(int);return 0;
}int odd_ones(unsigned x)
{int mask1 = 0x55555555;int mask2 = 0x33333333;int mask3 = 0x0F0F0F0F;int mask4 = 0x00FF00FF;int mask_odd_or_even = 1x = ((x >> 1)& mask1) + (x & mask1);x = ((x >> 2)& mask2) + (x & mask2);x = ((x >> 4)& mask3) + (x & mask3);x = ((x >> 8)& mask4) + (x & mask4);x = (x >> 16) + x;return x & mask_odd_or_even;
}
第二次尝试:
int odd_ones(unsigned x);int main(int argc, char const *argv[])
{unsigned x1 = 0xFF00FF00;unsigned x2 = 0xFF01FF00;printf("%d\t%d\n", odd_ones(x2), odd_ones(x1));return 0;
}int odd_ones(unsigned x)
{int mask1 = 0x55555555;int mask2 = 0x33333333;int mask3 = 0x0F0F0F0F;int mask4 = 0x00FF00FF;int mask_odd_or_even = 1;x = ((x >> 1)& mask1) + (x & mask1);x = x & mask1;x = (x >> 16) + x;x = x & mask1;x = (x >> 8) + x;x = x & mask1;x = (x >> 4) + x;x = x & mask1;x = (x >> 2) + x;return x & mask_odd_or_even;
}
*/
//第三次尝试:使用二分法/异或
#include <stdio.h>int odd_ones(unsigned x);int main(int argc, char const *argv[])
{unsigned x1 = 0xFF00FF00;unsigned x2 = 0xFF01FF00;printf("%d\t%d\n", odd_ones(x2), odd_ones(x1));return 0;
}int odd_ones(unsigned x)
{x = x ^ (x >> 16);x = x ^ (x >> 8);x = x ^ (x >> 4);x = x ^ (x >> 2);x = x ^ (x >> 1);return x & 1;
}

这个题的关键点在于如何表示偶数(将所有“1”相加末位为0)以及类似二分法的相加方法,同时注意到每次需要用用掩码将以前的高位置零。

这个题目是不会有“溢出”的情况的,因为1+1=10,10+10=0100,0100+0100=00001000......datalab实验里有一个相似的题目,那个题目更难一些。

以上想法在满足“Your code should contain a total of at most 12 arithmetic, bitwise, and logical
operations.”时出现了问题,根本原因在于二分法需要顾及到低位相加可能产生的进位,所以每次都需要用掩码将特定的高位置零,思路有点受到之前datalab实验的束缚(那个是要计算“1”的总数目)。这里计算的是“1”的数目的奇偶,不用考虑进位,异或运算是最佳选择,因为1+1和0+0均产生0(代表偶数),1+0和0+1均产生1(代表奇数)。

编译运行输出:

frank@under:~/tmp$ gcc 265.c && ./a.out
1   0

2.66

#include <stdio.h>
#include <limits.h>/** Generate mask indicating leftmost 1 in x. Assume w=32.* For example, 0xFF00 -> Ox8000, and Ox6600 --> Ox4000.* If x = 0, then return 0.*/int leftmost_one(unsigned x);int main(int argc, char const *argv[])
{printf("%#.8x\n", leftmost_one(0xFF00));printf("%#.8x\n", leftmost_one(0x6600));printf("%#.8x\n", leftmost_one(0x88886600));printf("%#.8x\n", leftmost_one(0));return 0;
}int leftmost_one(unsigned x)
{unsigned sizeof_unsigned = sizeof(unsigned);unsigned w = sizeof_unsigned << 3;x |= x >> 1;x |= x >> 2;x |= x >> 4;x |= x >> 8;x |= x >> 16;return x & ((~x >> 1)|INT_MIN);
}
/** Your code should contain a total of at most 15 arithmetic, bitwise, and logical* operations.* Hint: First transform x into a bit vector of the form [O · · · 011 · . · 1].*/

最后与INT_MIN做或运算是为了处理0x80000000这种边界情况,在这种情况下,~x >> 1由于没有更高位,而x又是unsigned类型,所以最高位会是0而非1,为了适应这种情况,强制将~x >> 1最高位置1。

编译运行输出:

frank@under:~/tmp$ gcc 266.c && ./a.out
0x00008000
0x00004000
0x80000000
00000000

另外,Web Asides http://csapp.cs.cmu.edu/3e/waside/waside-tneg.pdf 上面有一个利用-x和x的区别在于除最右1之前位翻转的特性求rightmost_one: x&-x, 有时间可以看看。


2.67

A:

(C11, 6.5.7p3) "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"

B:

#include <stdio.h>int int_size_is_32();int main(int argc, char const *argv[])
{printf("%d\n", int_size_is_32());return 0;
}int int_size_is_32()
{int set_msb = 1 << 31;int beyond_msb = set_msb;beyond_msb <<= 1;return set_msb && !beyond_msb;
}

编译运行输出:

frank@under:~/tmp$ gcc 267.c && ./a.out
1

C:

#include <stdio.h>int int_size_is_32();int main(int argc, char const *argv[])
{printf("%d\n", int_size_is_32());return 0;
}int int_size_is_32()
{int set_msb = 1 << 15;set_msb <<= 15;set_msb <<= 1;int beyond_msb = set_msb;beyond_msb <<= 1;return set_msb && !beyond_msb;
}

2.68

#include <stdio.h>int lower_one_mask(int n);int main(int argc, char const *argv[])
{printf("%#.8x\n", lower_one_mask(6));printf("%#.8x\n", lower_one_mask(17));return 0;
}int lower_one_mask(int n)
{int sizeof_int = sizeof(int);unsigned x = ~0;x >>= ((sizeof_int << 3) - n);return x;
}

编译运行输出:

frank@under:~/tmp$ gcc 268.c && ./a.out
0x0000003f
0x0001ffff

2.69

#include <stdio.h>unsigned rotate_left(unsigned x, int n);int main(int argc, char const *argv[])
{unsigned x = 0x12345678;printf("%#.8x\n", rotate_left(x, 0));printf("%#.8x\n", rotate_left(x, 4));printf("%#.8x\n", rotate_left(x, 20));return 0;
}unsigned rotate_left(unsigned x, int n)
{unsigned sizeof_unsigned = sizeof(unsigned);unsigned w = sizeof_unsigned << 3;unsigned mask = ((1 << n)-1) << (w-n);unsigned cache = (mask & x) >> (w-n);x <<= n;return x | cache;
}

关键点在于掩码的产生和移除位数据的保存。

编译运行输出:

frank@under:~/tmp$ gcc 269.c && ./a.out
0x12345678
0x23456781
0x67812345

2.70

#include <stdio.h>
#include <limits.h>int fits_bits(int x, int n);int main(int argc, char const *argv[])
{/*test short and 31bits*/printf("%d\n", fits_bits(-32768, 16));printf("%d\n", fits_bits(32767, 16));printf("%d\n", fits_bits(INT_MAX, 32));printf("%d\n", fits_bits(INT_MIN, 32));printf("%d\n", fits_bits(0, 16));printf("%d\n", fits_bits(0, 32));printf("%d\n", fits_bits(32768, 16));printf("%d\n", fits_bits(-32769, 16));printf("%d\n", fits_bits(INT_MIN, 31));printf("%d\n", fits_bits(INT_MAX, 31));return 0;
}int fits_bits(int x, int n)
{unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 3;int y = x << (w-n) >> (w-n);return y == x;
}

编译运行输出:

frank@under:~/tmp$ gcc 270.c && ./a.out
1
1
1
1
1
1
0
0
0
0

2.71

/* Declaration of data type where 4 bytes are packed into an unsigned */
typedef unsigned packed_t;
/* Extract byte from word. Return as signed integer */
int xbytte(packed_t word, int bytenum);
/*That is, the function will extract the designated byte and sign extend it to be
a 32-bit int.
Your predecessor (who was fired for incompetence) wrote the following code:*///Failed attempt at xbyte:int xbyte(packed_t word, int bytenum)
{
return (word>> (bytenum << 3)) & OxFF;
}
//A. What is wrong with this code?//B. Give a correct implementation of the function that uses only left and right
//shifts, along with one subtraction.

A:

当取出的字节为负数时,由于原操作“粗暴”的将高位置零,会返回一个错误的正值。

B:

#include <stdio.h>typedef unsigned packed_t;int xbytte(packed_t word, int bytenum);int main(int argc, char const *argv[])
{packed_t word = 0x8008FF00;printf("%d\n", xbytte(word, 0));printf("%d\n", xbytte(word, 1));printf("%d\n", xbytte(word, 2));printf("%d\n", xbytte(word, 3));return 0;
}int xbytte(packed_t word, int bytenum)
{unsigned left_move = (3 - bytenum) << 3;unsigned right_move = (3) << 3;return (int)word << left_move >> right_move;
}

编译运行输出:

frank@under:~/tmp$ gcc 271.c && ./a.out
0
-1
8
-128

2.72

/*BUGGY: Copy integer into buffer if space is available */
void copy_int(int val; void *buf, int maxbytes)
{if (maxbytes-sizeof(val) >= 0)memcpy(buf, (void*) &val, sizeof(val));
}

A:

sizeof返回的类型为size_t:

According to the 1999 ISO C standard (C99), size_t is an unsigned integer type of at least 16 bit (see sections 7.17 and 7.18.3).

size_tis an unsigned data type defined by several C/C++ standards, e.g. the C99 ISO/IEC 9899 standard, that is defined in stddef.h.1 It can be further imported by inclusion ofstdlib.h as this file internally sub includes stddef.h.

所以maxbytes-sizeof(val)将一直转化为无符号数并永远大于等于零。

B:

void copy_int(int val; void *buf, int maxbytes)
{if(maxbytes < 0)return;if (maxbytes >= sizeof(val))memcpy(buf, (void*) &val, sizeof(val));
}

2.73

#include <stdio.h>
#include <limits.h>int saturating_add(int x, int y);int main(int argc, char const *argv[])
{printf("%d\n", saturating_add(123456, -54321));printf("%d\n", saturating_add(2147483647, 1));printf("%d\n", saturating_add(-2147483648, -1));return 0;
}int saturating_add(int x, int y)
{unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 8;int i = (x ^ y) >> (w-1);//+-:FFFFFFFF ++/--:00000000int j = ((x+y) ^ x) >> (w-1);//overflow:FFFFFFFF otherwise:00000000int k = x >> (w-1);//+:00000000 -:FFFFFFFFreturn (i & (x + y)) + (~i & (j & ( (~k & INT_MAX) + (k & INT_MIN) )));
}

解释一下i j k:这三个变量和与运算结合用来做“判断语句”,i通过x,y是否异号判断是否可能溢出,j通过结果和加数的符号判断在同号的情况下是否发生溢出。k判断是应该返回INT_MAX 还是 INT_MIN。

编译运行输出:

frank@under:~/tmp$ gcc 273.c && ./a.out
69135
2147483647
-2147483648

2.74

#include <stdio.h>
#include <limits.h>int tsub_ok(int x, int y);int main(int argc, char const *argv[])
{printf("%d\n", tsub_ok(123456, 54321));printf("%d\n", tsub_ok(2147483647, -1));printf("%d\n", tsub_ok(-2147483648, 1));return 0;
}int tsub_ok(int x, int y)
{unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 8;y = -y;int i = (x ^ y) >> (w-1);//+-:FFFFFFFF ++/--:00000000int j = ((x+y) ^ x) >> (w-1);//overflow:FFFFFFFF otherwise:00000000return i || ~j;
}

原理与2.73类似。

编译运行输出:

frank@under:~/tmp$ gcc 274.c && ./a.out
1
0
0

2.75

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>unsigned unsigned_high_prod(unsigned x, unsigned y);
int signed_high_prod(int x, int y);int main(int argc, char const *argv[])
{/* code */return 0;
}unsigned unsigned_high_prod(unsigned x, unsigned y)
{unsigned w = sizeof(int32_t) << 3;int64_t signed_total_prod = signed_high_prod(x, y);signed_total_prod <<= w;signed_total_prod += x*y;bool x_w = x < 0 ? true : false;bool y_w = y < 0 ? true : false;int64_t unsigned_total_prod = signed_total_prod + ((x_w*(int)y + y_w*(int)x)<<w) + x_w*y_w<<(w*2);return (unsigned)(unsigned_total_prod>>w);
}

原理参见树上2.18等式。


2.76

void *calloc(size_t nmemb, size_t size)
{void *p;if(!(nmemb*size) || !(p = malloc(size*nmemb)))return NULL;else if (((size_t)(nmemb*size))/size != nmemb){printf("Too large space to calloc.\n");return NULL;}else{memset(p, 0, size*nmemb);return p;}
}

2.77

#include <stdio.h>int main(int argc, char const *argv[])
{unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 3;int x = 1;printf("%d\n", (x << 4) + x);//k=17printf("%d\n", x - (x << 3));//k=-7printf("%d\n", (x << 6) - (x << 2));//k=60printf("%d\n", (x << 4) - (x << 7));//k=-112return 0;
}

编译运行输出:

frank@under:~/tmp$ gcc 277.c && ./a.out
17
-7
60
-112

2.78

#include <stdio.h>int divide_power2(int x, int k);int main(int argc, char const *argv[])
{printf("%d\n", divide_power2(1024, 2));printf("%d\n", divide_power2(5, 2));printf("%d\n", divide_power2(-1024, 2));printf("%d\n", divide_power2(-5, 2));return 0;
}int divide_power2(int x, int k)
{int bias = (1 << k) - 1;unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 3;int judge = x >> (w-1); //-:FFFFFFFF +:00000000return (judge & ((x + bias) >> k)) + (~judge & (x >> k));
}

编译运行输出:

frank@under:~/tmp$ gcc 278.c && ./a.out
256
1
-256
-1

2.79

int mul3div4(int x)
{int k = 2;int bias = (1 << k) - 1;unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 3;x = (x << 1) + x;int judge = x >> (w-1); //-:FFFFFFFF +:00000000return (judge & ((x + bias) >> k)) + (~judge & (x >> k));
}

2.80

int threefourths(int x)
{int k = 2;int bias = (1 << k) - 1;unsigned sizeof_int = sizeof(int);unsigned w = sizeof_int << 3;int judge = x >> (w-1); //-:FFFFFFFF +:00000000x = (judge & ((x + bias) >> k)) + (~judge & (x >> k));return (x << 1) + x;
}

参考2.78


2.81

A:

x = ~0 << k;

B:

x = ~(~0 << k) << j;

2.82

A: when x = INT_MIN, y = 0. Yields 0

B: It always yields 1. Say, "mod" = mod 2^32. LEFT = ((((((x+y)mod)*16)mod)+y)mod)-x)mod = (17y + 15x)mod. RIGHT = (17*y)mod + (15*x)mod = (17y + 15x)mod.

C: It always yields 1. LEFT = (~x + 1) + (~y + 1) - 1 = -x + -y - 1. RIGHT = ~(x+y) + 1 - 1 = -(x+y) - 1 = -x + -y - 1.

D: It always yields 1. Since whether a integer type data is a int or unsigned doesn't influence the implementations of subtraction or unary minus operators.

(写到一半突然发现是用英文写的,可能是看教材影响的。。。)

E: 永远产生1,因为x先向右移动,再向左移动相同的位置,所以数据的高位不会受到影响。但是如果低两位有1的话,会都变为0。因为低位的1在补码中无论对于负数还是正数都是加的。所以对于正数来说,值会变小或者不变;对于0来说,值会不变;对于负数来说,值会变小或者不变。


2.83

A:

根据提示:Y = x*2^k - x 即 x = Y/(2^k - 1)

B:

由A:(a) Y = 101 = 5, k = 3, x = 5/7 (b) Y = 0110 = 6, k = 4, x = 2/5 (c) Y = 010011 = 19, k = 6, x = 19/63


2.84

#include <stdio.h>int float_le(float x, float y);
unsigned f2u(float x);int main(int argc, char const *argv[])
{printf("%d\n", float_le((float)1.11, (float)1.10));printf("%d\n", float_le((float)-1.2, (float)3.0));printf("%d\n", float_le((float)1.3, (float)1.3));printf("%d\n", float_le((float)0, (float)0));printf("%d\n", float_le((float)-1.1, (float)0));printf("%d\n", float_le((float)0, (float)1.1));return 0;
}unsigned f2u(float x)
{return *(unsigned*)&x;
}int float_le(float x, float y)
{unsigned ux = f2u(x);unsigned uy = f2u(y);/*Get the sign bits*/unsigned sx = ux >> 31; //+:0 -:1unsigned sy = uy >> 31;/* Give an expression using only ux, uy, sx, and sy */return (sx ^ sy) ? (sx ? 1 : 0)/*-+ +-*/ : (sx ? (ux>=uy) : (ux<=uy))/*-- ++*/;
}

编译运行输出:

frank@under:~/tmp$ gcc 284.c && ./a.out
0
1
1
1
1
1

2.85

bias = 2^(k-1) - 1 suppose that k <= n

A:

E = 0b10+bias, M = 0b1.11, f = ob1100*, V = 1.0

bit representation: 0, 0b10+bias, 1100*

B:

E = n+bias, M = 0b1.11*, f = 0b11*, V = 2^(n+1)-1

bit representation: 0, n+bias, 11*

C:

The smallest positive normalized value : E = 0b00*1, M = 0b1.00*, f = 0b00*, V = 1.0

So the reciprocal is exactly the same number.


2.86

bias = 2^14 - 1

Smallest positive denormalized:

Value: 0, 00*, 0, 00*1 Decimal:2^(2-2^14) * 2^(-63)

Smallest positive normalized:

Value: 0, 00*1, 1, 00* Decimal:2^(2-2^14)

Largest normalized:

Value: 0, 11*0, 1, 11* Decimal: 2^(2^14-1) * (2-2^(-63))


2.872.88本来在Typora上是用表格写的,上传上来好像有格式问题,将就看一下 ; )

2.87

| Description | Hex | M | E | V | D |
| -0 | 8000 | 0 | -14 | 0 | 0 |
| Smallest value > 2 | 4001 | 1025/1024 | 1 | 10252^-8 | 2.001953 |
| 512 | 6000 | 1 | 9 | 1
2^9 | 512.000000 |
| Largest denormalized | 0311 | 1023/1024 | -14 | 10232^-24 | 0.000061 |
| negative infinite | FC00 | - | - | - | -inf |
| 3BB0 | 3BB0 | 124/64 | -1 | 31
2^-5 | 0.968750 |


2.88

| Format A | Format A | Format B | Format B |
| Bits | Value | Bits | Value |
| 1 01111 001 | -9/8 | 1 0111 0010 | -9/8 |
| 0 10110 011 | 112^4 | 0 1110 0110 | 112^4 |
| 1 00111 010 | -52^-10 | 1 0000 0101 | -52^-10 |
| 0 00000 111 | 72^-17 | 0 0000 0001 | 2^-10 |
| 1 11100 000 | -2^13 | 1 1110 1111 | -31
2^3 |
| 0 10111 100 | 32^7 | 0 1110 1111 | 312^3 |


2.89

A:总是返回1.因为int到double不会有精度上的损失,所以x,dx转float(损失精度)的结果是一样的。

B:不总是返回1.如x=INT_MIN,Y=1。

C:不总是返回1.浮点数不满足结合律,如dx=1e30, dy=-1e30, dz=1e-30。

D:不总是返回1.原因同上。例如dx与dy互为倒数且dy*dz=+infinite。

E:不总是返回1.例如dx=1.0, dz=0.0 。


2.90

float fpwr2(int x)
{/* Result exponent and fraction */unsigned exp, frac;unsigned u;if (x < -149){/* Too small. Return 0.0 */exp = 0;frac = 0;} else if (x < -126) {/* Denormalized result */exp = 0;frac = 1 << (149 + x);}else if (x < 128){/* Normalized result. */exp = x + 127;frac = 0;}else{/* Too big. Return +oo */exp = 0xFF;frac = 0; }/*Pack exp and frac into,32 bits */u = exp << 23 | frac;/* Return as float */return u2f(u);
}

2.91

0x 40490FDB = 0b 0100 0000 0100 1001 0000 1111 1101 1011 = 0,10000000,10010010000111111011011

A: 10010010000111111011011

B: (详情可见)2.83 y=1, k=3, 即 0b11.(001)*

C: 0x4049039b 0x40492492 从高位向低位第19个。



浮点数部分由于时间所限,没有进行相关测试,思路大致应该是对的,可能会有一些边界/特殊情况会产生问题,欢迎指出。

2.92

float_bits float_negate(float_bits f)
{unsigned sign = f >> 31;unsigned exp = f >> 23 & 0xFF;unsigned frac = f & 0x7FFFFF;if(!(exp ^ 0xFF) && frac){return f;}else{sign = !sign;return (sign << 31) | (exp << 23) | frac;}
}

2.93

float_bits float_absval(float_bits f)
{unsigned exp = f >> 23 & 0xFF;unsigned frac = f & 0x7FFFFF;if(!(exp ^ 0xFF) && frac){return f;}return (exp << 23) | frac;
}

2.94

float_bits float_twice(float_bits f)
{unsigned sign = f >> 31;unsigned exp = f >> 23 & 0xFF;unsigned frac = f & 0x7FFFFF;if(!(exp ^ 0xFF)){if (frac)//NaN{return f;}/*else{return (sign << 31) | (exp << 23) | frac;//infinite}*/}else//Denormalnized and normalized{if (exp)//Normalnized{if (!(frac >> 22)){frac <<= 1;//return (sign << 31) | (exp << 23) | frac;}else if (!(exp ^ 0xFE)){++exp;//return (sign << 31) | (exp << 23) | frac;}else//overflow{frac = 0;exp = 0xFF;//return (sign << 31) | (exp << 23) | frac;}}else//Denormalized{if (!(frac >> 22)){frac <<= 1;//return (sign << 31) | (exp << 23) | frac;}else//Turn to Normalized{++exp;frac = frac << 10 >> 9;//set the 23th bit of frac to 0 and then left shift one bit.(注释是必要的。。。过了几天看这一段的时候自己也没弄懂,忘了这里frac是一个unsigned。。。) //return (sign << 31) | (exp << 23) | frac;}}}return (sign << 31) | (exp << 23) | frac;
}

2.95

float_bits float_half(float_bits f)
{unsigned sign = f >> 31;unsigned exp = f >> 23 & 0xFF;unsigned frac = f & 0x7FFFFF;if(!(exp ^ 0xFF)){if (frac)//NaN{return f;}/*else{return (sign << 31) | (exp << 23) | frac;//infinite}*/}else//Denormalnized and normalized{if (exp)//Normalnized{if (exp != 1){--exp;//return (sign << 31) | (exp << 23) | frac;}else//Turn to Denormalnized{if (frac)//maybe need to round to even{if ((frac >> 1)&1){++frac;frac >>= 1;frac |= 0x400000;--exp;}else{frac >>=1;frac |= 0x400000;--exp;}}}}else//Denormalized{if (frac)//maybe need to round to even{if ((frac >> 1)&1){++frac;frac >>= 1;}else{frac >>= 1;}}}}return (sign << 31) | (exp << 23) | frac;
}

2.96

int float_f2i(float_bits f)
{unsigned sign = f >> 31;unsigned exp = f >> 23 & 0xFF;unsigned frac = f & 0x7FFFFF;unsigned bias = 127;int flag = 0;if(sign)//<=0{if (f < 0xBF800000)//>-1{return 0;}else if (f <= 0xCF000000){if (f == 0xCF000000)//INT_MIN{return INT_MIN;//0x80000000;}else{f &= 0x7FFFFFFF;//first treat it as a positive numberflag = 1;goto A;B:return (~f + 1);//-(+int)}}else//overflow/-infinite/NaN{return 0x80000000;}}else//>=0{if (f < 0x3F800000)//<1//Denormalnized->0{return 0;}else if (f <= 0x4EFFFFFF){A:frac |= 0x800000;unsigned move = 23 - (exp-bias);if (flag)//jumped from a negative number{f = move >= 0 ? frac >> move : frac << -move;goto B;}else{return move >= 0 ? frac >> move : frac << -move; } }else//overflow/+infinite/NaN{return 0x80000000;}}
}
标准答案/* Compute (int) f. If conversion causes overflow or f is NaN, return 0x80000000 */int float_f2i(float_bits f) {unsigned sign = f >> 31;unsigned exp = (f >> 23) & 0xFF;unsigned frac = f & 0x7FFFFF;/* Create normalized value with leading one inserted, and rest of significand in bits 8--30./unsigned val = 0x80000000u + (frac << 8);if (exp < 127) {/* Absolute value is < 1 */return (int) 0;}if (exp > 158)/* Overflow */return (int) 0x80000000u;/* Shift val right */val = val >> (158 - exp);/* Check if out of range */if (sign) {/* Negative */return val > 0x80000000u ? (int) 0x80000000u : -(int) val;} else {/* Positive */return val > 0x7FFFFFFF ? (int) 0x80000000u : (int) val;}}

2.97

int leftmost_one(unsigned x)
{unsigned sizeof_unsigned = sizeof(unsigned);unsigned w = sizeof_unsigned << 3;x |= x >> 1;x |= x >> 2;x |= x >> 4;x |= x >> 8;x |= x >> 16;return x & ((~x >> 1)|INT_MIN);
}float_bits float_i2f(int i)
{unsigned sign = 0;unsigned exp = 0;unsigned frac = 0;unsigned bias = 127;if (i == INT_MIN){return 0xCF000000;}else//treat negative as positive{if (i < 0){sign = 1;i = -i;}int mask = leftmost_one(i);int move = 0;if (mask >= 0x00800000)//rightshift{while(mask != 0x00800000){mask >>= 1;++move;}if ((i & ((1 << (move+1)) - 1)) > (1 << move))//round to even(>1/2){i >>= move;i += 1;}else if((i & ((1 << (move+1)) - 1)) < (1 << move))//(<1/2){i >>= move;}else// 1/2{if ((i >> move)&1)//round to even{i >>= move;i += 1;}else{i >>= move;}}}else//leftshift{while(mask != 0x00800000){mask <<= 1;--move;}i <<= -move;}frac = i & 0x7FFFFF;//Discard the 24th bit oneexp = bias + 22 + move;}return (sign << 31) | (exp << 23) | frac;
}

用到了2.66产生标志整数最高位1掩码,从而判断应该左移或者右移多少位。

转载于:https://www.cnblogs.com/liqiuhao/p/7596539.html

深入理解计算机系统_3e 第二章家庭作业 CS:APP3e chapter 2 homework相关推荐

  1. 20135202闫佳歆-第二章家庭作业-2.69

    第二章家庭作业 选题:2.69 分值:三分 作业过程: 以下是rotate_right函数的代码: unsigned rotate_right(unsigned x, int n) {int endb ...

  2. 深入理解计算机系统(CSAPP) 第二章

    家庭作业 2.57 借助 C++ 模板可以很方便的实现. // g++ -o main main.cc -std=c++11 #include <string> #include < ...

  3. [第三章] 深入理解计算机系统第三版 家庭作业参考答案

    人非圣贤孰能无过,欢迎大家提问与纠错 3.58 long decode2(long x, long y, long z) {y -= z;x *= y;return ((y << 63) ...

  4. [第六章] 深入理解计算机系统第三版 家庭作业参考答案

    6.22 磁道数 d 与 r - x * r 成正比 设 d = k(r - x * r) = kr(1 - x) 总容量 c = 2πxk(r^2)(1 - x) = 2πk(r^2)(x - x^ ...

  5. [第五章] 深入理解计算机系统第三版 家庭作业参考答案

    5.13 A. 画图: 关键路径为第三幅图加粗部分 B. 下界为浮点加法的延迟界限,CPE 为 3.00 C. 整数加法的延迟界限,CPE 为 1.00 D. 关键路径上只有浮点加法 5.14 voi ...

  6. 深入理解计算机系统_第二章_信息的表示和处理

    深入,并且广泛-沉默犀牛 文章目录 文章导读 信息的表示和处理 信息存储 十六进制表示法 字数据大小 寻址和字节顺序 表示字符串 表示代码 布尔代数简介 C语言中的位级运算 C语言中的逻辑运算 C语言 ...

  7. 吾读 - 《深入理解计算机系统》第二章 信息的表示与处理 (二)浮点

    浮点数绝对是计算机系统里最神秘的一种数值.在不了解它之前,很难想象同样是32位数值,int只能表示最大2的31次方,而浮点的表示范围却是-126到正的127次方. 以及浮点还能表示无穷大,NaN等特殊 ...

  8. 计算机系统中处理的信息是什么,《深入理解计算机系统》第二章 信息的表示和处理...

    2.1信息存储 机器程序将内存视为一个很大的字节数组,称为虚拟内存.所有可能的地址集合称为虚拟地址空间,实际上,该功能的实现是将动态随机访问存储器(DRAM).闪存.磁盘存储器.特殊硬件和操作系统软件 ...

  9. CSAPP 第二章家庭作业2.70

    /* * fitsBits - return 1 if x can be represented as an * n-bit, two's complement integer.0 otherwise ...

最新文章

  1. 2410Init.s
  2. Demo:充分利用 Ajax 技术 来体现页面局部刷新 效果(获取天气预报情况)
  3. android:layout_width=0.0dip,【教程】状态栏显示网速
  4. java验证码的代码_java实用验证码的实现代码
  5. python怎么安装xlrd库_Python第三方库xlrd/xlwt的安装与读写Excel表格
  6. 网络I/O模型--04非阻塞模式(解除accept()、 read()方法阻塞)的基础上加入多线程技术...
  7. ACM-线段树区间更新+离散化
  8. Swift 枚举简单使用
  9. 基于PSR-0编码规范开发一套PHP-MVC框架(二)
  10. java生成pdf旋转_Java 添加、删除、旋转PDF页面
  11. windows未能启动计算机,电脑开机windows未能启动是怎么回事
  12. 新增10所高校获批虚拟现实技术本科专业,中国市场将超千亿
  13. css3制作广告栏效果的疑问? 1
  14. 华为手机卡在升级界面_华为通用强制升级教程 华为官方卡刷教程
  15. 求50以内的全部素数
  16. 彩色流程图怎么做?这样的操作方法你尝试过吗?
  17. crc-16 ccitt标准在哪里可以看到详细的
  18. [置顶]援引个人新浪博客
  19. Matlab概率论与数理统计实践-假设检验
  20. Python备份CSDN博客的完整页面

热门文章

  1. 【锐捷交换】接入交换机安全配置
  2. 【汇编语言实战】一元二次方程ax2+bx+c=0求解(含源码与过程截屏,可修改参数)
  3. 【Git技巧】第三篇 删除冗余的本地或远程的操作分支
  4. 神经网络解决推荐系统问题(NCF)
  5. idea下git 错误 error: unable to read askpass response from 'C:\Users\ASUS\.IntelliJIdea2019.1\system\tm
  6. android 固定launcher,android 开机默认进入指定Launcher
  7. 【SQL学习笔记】《SQL进阶教程》1.1
  8. oim failed_对OIM Web(UI)层进行压力测试
  9. Witt向量简介 §3.2:Witt向量的环结构概述
  10. Vitis开发笔记:将镜像刻录到SD卡