CSAPP 第三版 第二章 家庭作业and so on

CSAPP 第三版 第二章 作业
自己做的 仅供参考 可能出现错误
发现几乎网上相关 -1 均表示为~0 不知道为啥23333

注:2.65 2.66 2.73 2.75 2.80 2.95 2.96 2.97 mark一下

2.55-2.57

2.58

int is_little_edian()  
{  
    int n = 0xcd23ff;  
    int ch = *(unsigned char *)&n;  
    return ch == 0xff;  
}

备注:
开始的时候用的是*(char * ),结果输出ch了是0xffff,想了想应该是因为先取出ff然后char是有符号的,按有符号的规则进行扩展扩展到32位于是在ff前补充11111111(即ff),所以不能用char应该用unsigned char来代替

2.59

开始看得有点懵,后来才知道最低有效字节是LSB啊,换了个说法……
不过看例子还是能猜到的

(x & 0xFF) | (y & ~0xFF)

2.60

unsigned replace_byte(unsigned x, int i, unsigned char b)
{
	i <<= 3;
	return b << i | (x & ~(0xFF << i));
}

  原来单写了 b <<= i,应该放在 return 语句让其发生强制类型转换的!

2.61

题目以为要判断四个条件同时成立,还在想说第一个条件不应该隶属于第三个条件,第二个条件不应该隶属于第四个条件么……emmm发现是我想多了,题目不难,我的答案里并没有对int的长度作出假设(没有假设int为4字节)

> A. !(~x);
> B. !x;
> C. !~((-1 << 8) | x);
> D. !(x >> ((sizeof(x) << 3) - 8));

默认一字节=8位
看了网上好多答案,发现可能是题目不一样,下面是我的书的题目

C.x的最低有效字节中的位都等于1
D.x的最高有效字节中的位都等于0

2.62

int int_shifts_are_arithmetic()
{
	return !(~(-1 >> 1));
}

2.63

unsigned sr1(unsigned x, int k)
{
	/* Perform shift arithmetically */
	unsigned xsra = (int)x >> k;
	return xsra & (-1 << (sizeof(int) * 8 - k));
}
int sra(int x, int k)
{
	/* Perform shift logically */
	int xsrl = (unsigned)x >> k;
	int m = x & (0x1 << sizeof(int) * 8 - 1);
	return xsrl + (((!m) + -1) << (sizeof(int) * 8 - k));
}

2.64

/* Return 1 when any odd bit of x equals 1; 0 otherwise.
   Assume w=32 */
int any_odd_one(unsigned x)
{
	return !~(x & 0x55555555 | 0xaaaaaaaa);
}

2.65

这道题琢磨了挺久,先把一半的数与另一半的数异或,若恰巧异或结果为0(0,0:这种情况无1不计数;0,1或1,0:这种情况计数为1留到下一轮;1,1:偶数个异或为0,就不考虑了,奇/偶数个+偶数个还是奇/偶数个)

/* Return 1 when x contains an odd number of 1s; 0 otherwise
   Assume w=32 */
int odd_ones(unsigned x)
{
	x ^= (x >> 16);
	x ^= (x >> 8);
	x ^= (x >> 4);
	x ^= (x >> 2);
	x ^= (x >> 1);
	return !!(x & 0x1);
}

  更新:

  这么做:在计数含有 32 位的数 a 0 a 1 a 2 . . . a 30 a 31 a_0a_1a_2...a_{30}a_{31} a0a1a2...a30a31 含有的 1 的个数时,由于异或 ⨂ \bigotimes 运算 1 ⨂ 1 = 0 1 \bigotimes 1 = 0 11=0 (偶数个 1 结果为 0), 1 ⨂ 0 = 1 1 \bigotimes 0 = 1 10=1(奇数个 1 结果为 1。严格证明可以用数学归纳法) 的特性,我们可以计数 1 1 1 的个数。
  通常思路是: a 0 ⨂ a 1 ⨂ . . . ⨂ a 31 a_0\bigotimes a_1\bigotimes...\bigotimes a_{31} a0a1...a31,由于运算满足交换律以及结合律,我们可以转变为:
r e s u l t = a 0 ⨂ a 1 ⨂ . . . ⨂ a 31 = ( a 0 ⨂ a 16 ) ⨂ ( a 1 ⨂ a 17 ) . . . ( a 15 ⨂ a 31 ) ≜ ( b 16 ) ⨂ ( b 17 ) . . . ⨂ ( b 31 ) = ( b 16 ⨂ b 24 ) ⨂ . . . ⨂ ( b 23 ⨂ b 31 ) ≜ ( c 24 ) ⨂ ( c 25 ) . . . ⨂ ( c 31 ) = ( c 24 ⨂ c 28 ) ⨂ . . . ⨂ ( c 27 ⨂ c 31 ) = . . . \begin{aligned} result &= a_0\bigotimes a_1\bigotimes...\bigotimes a_{31}\\ &=(a_0\bigotimes a_{16})\bigotimes (a_1\bigotimes a_{17})...(a_{15}\bigotimes a_{31})\\ &≜(b_{16})\bigotimes (b_{17})...\bigotimes (b_{31})\\ &=(b_{16}\bigotimes b_{24})\bigotimes...\bigotimes(b_{23}\bigotimes b_{31})\\ &≜(c_{24})\bigotimes (c_{25})...\bigotimes (c_{31})\\ &=(c_{24}\bigotimes c_{28})\bigotimes...\bigotimes(c_{27}\bigotimes c_{31})\\ &=... \end{aligned} result=a0a1...a31=(a0a16)(a1a17)...(a15a31)(b16)(b17)...(b31)=(b16b24)...(b23b31)(c24)(c25)...(c31)=(c24c28)...(c27c31)=...

  等式第一行是原式,第二行进行交换律与结合律,对应代码的第 5 5 5 行,结果为 b 0 b 1 b 2 . . . b 30 b 31 b_0b_1b_2...b_{30}b_{31} b0b1b2...b30b31,只需看 b 16 b 17 . . . b 30 b 31 b_{16}b_{17}...b_{30}b_{31} b16b17...b30b31
  等式第三行进行交换律与结合律,对应代码的第 6 6 6 行,结果为 c 0 c 1 c 2 . . . c 30 c 31 c_0c_1c_2...c_{30}c_{31} c0c1c2...c30c31,只需看 c 24 c 25 . . . c 30 c 31 c_{24}c_{25}...c_{30}c_{31} c24c25...c30c31
  以此类推可得结果。


2.66

受到上一题的启发,同样每次折半或,将原来的数化为[0…111]位向量,然后右移一位加一就ok了

/* Generate mask indicating leftmost 1 in x. Assume w=32.
 * For example, 0xFF00 -> 0x8000, and 0x6600 --> 0x4000.
 * If x = 0, then return 0.
 */
int leftmost_one(unsigned x)
{
	x |= (x >> 16);
	x |= (x >> 8);
	x |= (x >> 4);
	x |= (x >> 2);
	x |= (x >> 1);
	return (x >> 1) + 0x1;
}

2.67

A. C语言的移位操作符规定移位数应小于机器字长,C语言并没有对大于等于机器字长的移位要求做出明确要求与处理方式

B.

/* The following code does not run properly on some machines */
int bad_int_size_is_32()
{
	/* Set most significant bit (msb) of 32-bit word */
	int set_msb = 1 << 31;
	/* Shift past msb of 32-bit word */
	int beyond_msb = set_msb << 1;

	/* set_msb is nonzero when word size >= 32 
	   beyond_msb is zero when word size <= 32 */
	return set_msb && !beyond_msb;
}

C.

int bad_int_size_is_32()
{
	/* Set most significant bit (msb) of 32-bit word */
	int set_msb = 1 << 15 << 15 << 1;;
	/* Shift past msb of 32-bit word */
	int beyond_msb = set_msb << 1;

	/* set_msb is nonzero when word size >= 32 
	   beyond_msb is zero when word size <= 32 */
	return set_msb && !beyond_msb;
}

2.68

/*
 * Mask with least significant n bits set to 1
 * Examples: n = 6 --> 0x3F, n = 17 -->0x1FFFF
 * Assume 1 <= n <= w
 */
int lower_one_mask(int n)
{
	return 1 << (n - 1) << 1;
}

2.69

/*
 * Do rotating left shift. Assume 0 <= n < w
 * Examples when x = 0x12345678 and w = 32:
 *    n=4 -> 0x 23456781, n=20 -> 0x67812345
 */
unsigned rotate_left(unsigned x, int n)
{
	int t = 1 << ((sizeof(int) << 3) - 1);
	int m = t >> n;
	int sm = ((int)x & m) >> ((sizeof(int) << 3) - n - 1) >> 1;//防止括号里面超过w
	return sm | (x << n);
}

2.70

/* 
 * Return 1 when x can be represented as an n-bit, 2's-complement 
 * number; 0 otherwise 
 * Assume 1 <= n <= w 
 */  
6.int fits_bits(int x, int n)  
7.{  
8.    int t = x >> (n - 1);  
9.    return !(t && ~t);  
}

2.71

A. 根据符号扩展的规则,如果该字节(MSB为符号位)为负数,则按要求应拓展为[111…]形式,而给出的bug代码中不能完成这个操作

B.

/* 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 xbyte(packed_t word, int bytenum)
{
	int left = (sizeof(int) - 1 - bytenum) << 3;
	int right = (sizeof(int) - 1) << 3;
	return (unsigned)((int)word << left >> right);
}

2.72

A. sizeof(val)为unsigned,与maxbytes(int类型)运算时将全部转换为(unsigned)类型进行运算,于是maxbytes-sizeof(val) >= 0永真,故条件测试总是成功

B.

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

2.73

/* Addition that saturates to TMin or TMax */
int saturating_add(int x, int y)
{
	int TMin = 1 << ((sizeof(int) << 3) - 1) << 1;
	int TMax = TMin - 1;
	int sum = x + y;
	int m = (x & TMin) & (y & TMin) & !(sum & TMin);
	int n = !(x & TMin) & !(y & TMin) & (sum & TMin);
	(m && (sum = TMax)) || (n && (sum = TMin));
	return sum;
}

2.74

/* Determine whether arguments can be substracted without overflow */ 
int tsub_ok(int x, int y)  
{  
    int sum = x - y;  
    int neg_over = x < 0 && y > 0 && sum >= 0;  
    int pos_over = x >= 0 && y <= 0 && sum < 0;  
    return !neg_over && !pos_over;  
}  

2.75

//#include <stdint.h>
unsigned unsigned_high_prod(unsigned x, unsigned y)
{
	uint64_t msb_x = (uint64_t)x >> ((sizeof(x) << 3) - 1);
	uint64_t msb_y = (uint64_t)y >> ((sizeof(x) << 3) - 1);
	uint64_t goal = (int)x * (int)y + signed_high_prod(x, y) << (sizeof(int) << 3) + (x * msb_y + y + msb_x) << (sizeof(int) << 3) + (msb_x * msb_y) << (((sizeof(int) << 3) << 1) - 1) << 1;
	return goal >> (sizeof(int) << 3);
}

2.76

//void *malloc(size_t size);
//void *memset(void *s, int c, size_t n);
void *calloc(size_t nmemb, size_t size)
{
	void *p;
	if (nmemb == 0 || size == 0)
	{
		return NULL;
	}
	size_t goal = size * nmemb;
	if (nmemb != goal / size)
	{
		return NULL;
	}
	p = malloc(goal);
	if (p == NULL)
	{
		return NULL;
	}
	memset(p, 0, goal);
	return p;
}

2.77

> A. x = x + (x << 4);
> B. x = x - (x >> 3);
> C. x = (x << 6) - (x << 2);
> D. x = (x << 4) - (x << 7);

2.78

/* Divide by power of 2. Assume 0 <= k < w-1 */  
int divide_power2(int x, int k)  
{  
    int bias = (x >> ((sizeof(int) << 3) - 1)) & ((1 << k) - 1);  
    return (x + bias) >> k;  
} 

2.79

int mul3div4(int x)
{
	x += x << 1;
	int bias = (x >> ((sizeof(int) << 3) - 1)) & ((1 << 2) - 1);
	return  (x + bias) >> 2;
}

2.80

int threefourths(int x)
{
	int later = x & 0x3;
	int former = x & ~0x3;
	int w = sizeof(int) << 3;
	int bias = (x >> (w - 1)) & ((1 << 2) - 1);
	former >>= 2;
	former = (former << 1) + former;
	later = (later << 1) + later;
	later = (later + bias) >> 2;
	return later + former;
}

2.81

> A. (~0) << k;
> B. (~((~0) << (k + j))) & ((~0) << j);

2.82

> A.当x=Tmin,y=0,该表达式为0;  
> B.该表达式总为1,因为17 * x + 15 * y = 16 * (x + y) + y - x = (x + y) << 4 + y - x;  
> C.该表达式总为1:由于~x = -x - 1, ~y = -y - 1,~x + ~y + 1 = -x - 1 + (-y - 1) + 1 = -x - y - 1,~(x + y) = -x - y - 1,故两式相等;  
> D.该表达式总为1,因为无符号与有符号加减法位级表示相同并且最终都为unsigned类型,故相等;  
> E.该表达式总为1,因为先右移再左移,最低位丢失或不丢失,故比移位前值不变或变小;  

2.83

> A. Y/(2^k-1);
> B. 
> ( a ).5/7;
> ( b ).2/5;
> ( c ).19/63;

2.84

int float_le(float x, float y)
{
	unsigned ux = f2u(x);
	unsigned uy = f2u(y);

	/* Get the sign bits */
	unsigned sx = ux >> 31;
	unsigned sy = uy >> 31;

	/* Give an expression using only ux, uy, sx, and sy */
	return ((ux << 1) == 0 && (uy << 1) == 0) || (sx && !sy) || (!sx && !sy && ux <= uy) || (sx && sy && ux >= uy);
}

2.85

> A.  E = 2 - (2^(k - 1) - 1) = 3 - 2^(k - 1), M = 1 + f = 1 + (2^(-1) + 2^(-2)) = 9/4, f = 5/4, V=2^E * M   0|10..01|110...0;
> B.  E = n, M = 1 + f = 2 - 2^(-n), f = 1 - 2^(-n), V = 2^E * M   0|1...1|1...1;
> C.  E = -(1 - (2^(k - 1) -1)) = 2^(k - 1) - 2, M = 1 + f = 1 + 0 = 1, f = 0, V = 2^E * M = 2^(2^(k - 1) - 2)     0|11... 01|0...0;

2.86

> 最小的正非规格化数::0|0...00|0|0...01|   十进制:E=1-bias=2-2^14=-16382,M=frac=2^(-63),故值为2^(-16445)= 3.645e-4951 ;
> 最小的正规格化数::0|0...01|1|0...00|   十进制:E=e-bias=2-2^14=-16382,frac=0,M=1+frac=1,故值为2^(-16382)= 3.362e-4932 ;
> 最大的规格化数::0|1...10|1|1...11|   十进制:E=e-bias=2^15-2-(2^14-1)=16383,frac=(2^(-1)+2^(-2)+...+2^(-63))=1-2^(-63),M=1+frac=2-2^(-63),故值为2^16383*(2-2^(-63))=1.190e+4932 ;

2.87

//%f默认保留6位小数!!!
> 0x8000        0      	 -14    	-0     	          -0.0
> 0x4001     1025/1024    15      1025/512           2.001953
> 0x0200        1         9         512               512.0
> 0x03FF     1023/1024   -14    1023/(2^(-24))       0.000061 
> 0xFC00        -         -         --> 0x3BB0       123/64    -1       123/128            0.960938

2.88

> 208        0|1110|1010      208
> -7/1024    1|0000|0111    -7/1024
> 5/2^17     0|0000|0001     1/2^10
> -2^12      1|1110|1111      -248
> 768        0|1111|0000      +

2.89

> A. 总为1,因为从int转换为double类型属于精确转换,则均转换为float时情况相同;
> B. 不总为1,x = TMIN, y = 1;
> C. 不总为1,x = 3.1415926, y = 1e300, z = -1e300;//浮点数加法不满足结合律
> D. 不总为1,x = 1e-308, y = 1e308, z = 9.7//浮点数乘法不满足结合律、分配率
> E. 不总为1,x = 1,y = 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 +0.0 */  
        exp = 255;  
        frac = 0;  
    }  
  
    /* Pack exp and frac into 32 bits */  
    u = exp << 23 | frac;  
    /* Return as float */  
    return u2f(u);  
}

2.91

> A. 0|10000000|10010010000111111011010
> B. 11.001001001001...
> C. 第九位

2.92

/* Access bit_level representation floating_point number */
typedef unsigned float_bits;
/* Compute -f. If f is NaN, then return f. */
float_bits float_negate(float_bits f)
{
	float_bits sign = f >> 31;
	float_bits exp = (f >> 23) & 0xFF;
	float_bits frac = f & 0x7FFFFF;
	if (exp == 0xFF && frac != 0)
	{
		return f;
	}
	sign = (~sign);
	return (sign << 31) | (exp << 23) | frac;
}

2.93

/* Access bit_level representation floating_point number */
typedef unsigned float_bits;
/* Compute |f|. If f is NaN, then return f. */
float_bits float_absval(float_bits f)
{
	float_bits exp = (f >> 23) & 0xFF;
	float_bits frac = f & 0x7FFFFF;
	if (exp == 0xFF && frac != 0)
	{
		return f;
	}
	return (0 << 31) | (exp << 23) | frac;
}

2.94

/* Access bit_level representation floating_point number */
typedef unsigned float_bits;
/* Compute 2*f. If f is NaN, then return f. */
float_bits float_twice(float_bits f)
{
	float_bits sign = f >> 31;
	float_bits exp = (f >> 23) & 0xFF;
	float_bits frac = f & 0x7FFFFF;
	if (exp == 0xFF && frac != 0)
	{
		return f;
	}
	if (exp == 0)
	{
		if (!(frac >> 22))
		{
			frac = (frac << 1);
		}
		else
		{
			exp = 1;
			frac = (frac << 1) & 0x7FFFFF;
		}
	}
	else
	{
		exp++;
		if (exp == 255)
		{
			frac = 0;
		}
	}
	return (sign << 31) | (exp << 23) | frac;
}

2.95

/* Access bit_level representation floating_point number */
typedef unsigned float_bits;
/* Compute 0.5*f. If f is NaN, then return f. */
float_bits float_half(float_bits f)
{
	float_bits sign = f >> 31;
	float_bits exp = (f >> 23) & 0xFF;
	float_bits frac = f & 0x7FFFFF;
	if (exp == 0xFF)
	{
		return f;
	}
	unsigned condition = ((f & 0x3) == 0x3);
	if (exp == 0)
	{
		frac = frac >> 1;
		frac += condition;
	}
	else if(exp == 1)
	{
		exp = 0;
		frac = (frac >> 1);
		frac += condition;
		frac |= 0x400000;
	}
	else
	{
		exp--;
	}
	return (sign << 31) | (exp << 23) | frac;
}

2.96

/* Access bit_level representation floating_point number */
typedef unsigned float_bits;
/*
 * Compute (int) f.
 * If conversion cause overflow overflow or f is NaN, return 0x80000000
 */
int float_f2i(float_bits f)
{
	float_bits sign = f >> 31;
	float_bits exp = (f >> 23) & 0xFF;
	float_bits frac = f & 0x7FFFFF;
	float_bits bias = 127;
	float_bits num;
	float_bits E, M;
	if (exp < bias)
	{
		num = 0;
	}
	else if (exp >= 31 + bias)
	{
		num = 0x80000000;
	}
	else
	{
		E = exp - bias;
		M = frac | 0x800000;
		if (E > 23)
		{
			num = M << (E - 23);
		}
		else
		{
			num = M >> (23 - E);
		}
	}
	return sign ? -(int)num : (int)num;
}

2.97

#include <limits.h>
/* Access bit_level representation floating_point number */
typedef unsigned float_bits;
/* Compute (float) i */
float_bits float_i2f(int i)
{
	float_bits sign, exp, frac, num, E, M;
	float_bits bias = 127;
	if (i == 0)
	{
		return 0;
	}
	if (i == INT_MIN)
	{
		sign = 1;
		exp = 31 + bias;
		frac = 0;
		return (sign << 31) | (exp << 23) | frac;
	}
	sign = i > 0 ? 0 : 1;
	if (i < 0)
	{
		i = -i;
	}
	float_bits bits = 0;
	float_bits ui = (float_bits)i;
	while (ui > 0)
	{
		ui >>= 1;
		++bits;
	}
	float_bits fbits = bits - 1;//2^fbits
	exp = bias + fbits;
	float_bits uux = (1 << (fbits - 1));
	uux |= uux >> 1;
	uux |= uux >> 2;
	uux |= uux >> 4;
	uux |= uux >> 8;
	uux |= uux >> 16;
	float_bits fb = uux & i;
	if (fbits <= 23)
	{
		frac = fb << (23 - fbits);
	}
	else//无法精确表示
	{
		float_bits j = fbits - 23;
		frac = fb >> j; 
		float_bits round_mid = 1 << (j - 1);
		float_bits uuy = (1 << (j - 1));
		uuy |= uuy >> 1;
		uuy |= uuy >> 2;
		uuy |= uuy >> 4;
		uuy |= uuy >> 8;
		uuy |= uuy >> 16;
		float_bits round_part = fbits & uuy;
		if (round_part > round_mid)
		{
			++frac;
		}
		else if (round_part == round_mid) 
		{
			if (frac & 0x1)
			{
				++frac;
			}
		}
	}
	return (sign << 31) | (exp << 23) | frac;
}
  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值