A. 反例:$x = -1, x - 1= 0$;
B. $x & 0111_2 \ne 0111_2$当$x$的低3位有1位等于0时即可成立,$x << 29 < 0$将$x$的低3位移到高三位。那么低三位如果全为1,后者为真,有0则前者为真,所以表达式恒为真;
C. 反例:$x$为一个比较大的正数,平方后超过$2^{31} - 1$;
D. 真:$x = Tmin, -x = Tmin$,其余情况x如果是负数,那么-x一定是非负数;
E. 反例:$x = Tmin, -x = Tmin$;
F. 真:首先,比较类型为无符号数比较;加法都按补码进行运算,两边二进制结果显然一致;
G.真:$-y = \sim y + 1\rightarrow \sim y = -y - 1\rightarrow x * \sim y + uy * ux = x * (-y + y - 1) = -x$;全部按二进制表示理解即可;
2.45
2.47
2.54
A. double范围和精度比int大;
B. 假,int转化为float可能会发生舍入;
C. 假,double转化为float会截断;
D. double范围和精度比float大;
E. 没毛病,只需改变符号位;
F. 两边都先转化为double类型再运算;
G. 没毛病,即使溢出到正无穷也是大于0;
H. 假,浮点数运算不满足结合律;
2.60
1 2 3 4 5 6 7 8
unsignedreplace_byte(unsigned x, int i, unsignedchar b) { int i_times_8 = i << 3; // 将字节单位转化为位; unsigned mask = 0xFF << i_times_8; // 将0xFF左移i个字节,得到第i个字节为FF,其余全为0的字符串; // x & ~mask 可以将x的第i个字节清0; // b << i_times_8 将b移动到第i个字节上; // 两者进行或运算即可实现替换; return (x & ~mask) | (b << i_times_8); }
2.65
1 2 3 4 5 6 7 8 9
intodd_ones(unsigned x) { // x的高位和低位进行异或,如果1对0,得到1;如果1对1或0对0,得到0,那么高位有奇数个1还是偶数个1的信息就被转移到低位中; x = x ^ (x >> 16); // 将x的高16位与低16位异或 x = x ^ (x >> 8); x = x ^ (x >> 4); x = x ^ (x >> 2); x = x & 1; return x; }
2.67
A. C标准中,在32位机器上,移位32位是一种未定义的行为;
B. 很简单,先移31位,再移一位即可;
1 2 3
int beyond_msb = 1 << 32; // 改为 int beyond_msb = set_msb << 1;
C. 类似地(16位机器上,移动n + 16位和移动n位效果一样);
1 2
int set_msb = 1 << 15; int beyond_msb = set_msb << 1;