CSAPP读书笔记第二章:

着一章主要介绍了数据才计算机里面的二进制存储,一些位运算的小技巧和一些程序中可能出现的错误。

[0] 高位取反低位不变:利用异或x^(~0xff)

[1] 利用位运算交换两个数:

y = x^y
x = y^x
y = y^x

注意,这一段代码存在一个隐藏的陷阱,如果x,y同时指向一个变量,那么第一步就会把这两个变量同时变成0,这样后面的答案全没有意义了。所以要注意这一点。

[2] 无符号和有符号之间的隐式转换造成的错误。

像下面这样的代码,如果length是无符号,那么-1这个运算就可能会产生错误。因为length可能会是0。所以比较好的习惯是写为i<length.
for(int i = 0;i<=length-1;++i){}

又比如下面这个例子:

int longer(char* s1,char* s2){
    return strlen(s1)-strlen(s2)>0;
}

由于strlen()返回的是size_t,而size_t是一个无符号整数,那么得到的结果就可能出错,所以通过这两个例子就可以得出一个结论:无符号整数不要轻易的进行减法运算。

[3]

补码有两种溢出情况,分别是正溢出和负溢出。假设整数是w位,那么对于 2w1x,y2w11

这里写图片描述

[4]

编译器有时候会优化成 a<<k1+a<<k2+a<<k3 …的形式。对于LEA指令,可以计算 a<<k+b ,考虑b是0或者a,我们可以利用一条LEA指令就计算出a的 2k2k+1

d

[5]

对于无符号数以及有符号数中的正数,除以 2k 可以写成 a>>k ,对于负数,我们需要写成 (a+2k1)>>k ,第二项的式子很容易通过把a写成 a=ky+r 来证明是正确的。

如果我们对于一个整数进行相应的2幂次除法,如何在不使用比较和判断符号的情况下完成上述的运算?如果这个整数是32位的,我们可以利用x = a>>31来获取答案。对于正数和负数,产生的结果是全1或者全0。

习题:

这里写图片描述

显然M=32,N=8。

习题:

这里写图片描述

这道题主要搞清楚溢出的情况,前面的答案分别是假,真,假,真,假,真,真。要注意补码运算和无符号数的运算在位运算截断之后是等价的,所以F正确。而对于G,因为~y = -(y+1),所以原来的式子就变成 x(y1)+xy=x ,所以正确。

[6]

(1)

x = 0.1
for i in range(20):
    x *= 2
    if x>1:print('1',end='')
    else:print('0',end='')
    x = x-1 if x>1 else x

(2):

这里写图片描述

这个计算出来大概有683m的误差。尽管浮点数在二进制表示的误差很小,但是在这个系统里面对误差的计算非常敏感。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值