CS:APP/深入理解计算机系统-第二章(2.3)

2.3节主要是介绍整数运算,在写代码的时候可能会遇见整数相加得出一个负数、x<y和x-y<0的结果不一致的现象。这是由于计算机运算的有限性导致的,本节可以帮助理解。

2.3.1 无符号加法

考虑两个非负整数x 和y, 满足0\leq x,y< 2^w 。每个数都能表示为w位无符号数字。然而,如果计算它们的和,我们就有一个可能的范围0\leq x+y\leq 2^{w+1}-2。表示这个和可能需要w+1位。然而一般来说,编程语言支持的是固定精度的运算,因此计算机上的“加法”和“乘法”这样的运算不用于它们在整数上的相应运算。

计算机上的无符号加法的定义是:

假设有两个数x和y,满足0\leq x,y< 2^w,计算出x+y之后,截断w位,得到的结果看作无符号数,作为计算机上x+y的和。公式表示为:

 公式里y的标志就表示无符号数加法,限制w位。

无符号数求反:

对于满足0\leq x< 2^w的任一个x,其w位的无符号逆元的公式表示如下:

 2.3.2 补码加法

对于补码加法,必须确定当结果太大(位正)或者结果太小(为负)时,应该做些什么。给定在范围-2^{w-1}\leq x,y\leq 2^{w-1}-1之内的整数值x和y,它们的和就在范围-2^w\leq x+y\leq 2^w-2之内,要想准确表示,可能需要w+1位。计算机需要像前面无符号加法一样,通过将最后的计算结果进行截断到w位,来避免数据大小的不断扩张,然后将截断后的结果看作是补码数。定义补码加法的公式表示如下:

 补码求反:

对于TMin_w\leq x\leq TMax_w的x,其补码求反结果如下所示:

 2.3.3 无符号乘法

范围在0\geq x,y\geq 2^w-1内的整数x和y可以被表示为w位的无符号数,但是它们的乘积x •y 的取值范围为0到(2^w-1)^2之间。这可能需要2w位来表示。不过, C 语言中的无符号乘法被定义为产生w位的值,就是2w位的整数乘积的低w位表示的值。我们将这个值表示为。公式表示如下:

 

 2.3.4 补码乘法

范围在-2^{w-1}\leq x,y\leq 2^{w-1}-1内的整数x 和y 可以被表示为w位的补码数字,但是它们的乘积x·y的取值范围为-2^{w-1}\cdot (2^{w-1}-1)-2^{w-1}\cdot -2^{w-1}之间。要想用补码来表示这个乘积,可能需要2w位。然而,C 语言中的有符号乘法是通过将2w位的乘积截断为w位来实现的。我们将这个数值表示为。将一个补码数截断为w位相当千先计算该值模2^{w} , 再把无符号数转换为补码。数学表示如下:

无符号乘法和补码乘法具有位级等价性,对于这个性质的直观理解可以看下图:

截断之后,只对比每个bit位,无符号乘法和补码乘法是完全相同的。 

2.3.5 乘以常数

以往,在大多机器上,乘法总是会比较慢(加法、减法、位级运算和移位只需要1个时钟周期,而乘法需要多个)。因此,编译器使用了一项重要的优化,试着用移位和加法运算的组合来代替乘以常数因子的乘法。首先,我们会考虑乘以2的幂的情况,然后再概括成乘以任意常数。 

与2的幂相乘分为无符号乘法和补码乘法。

对于无符号乘法,假设是2的k次幂,那么左移k位就可以。

对于补码乘法,假设是2的k次幂,同样是左移k位得到结果。

左移产生溢出之后,截断就可以,然后按着无符号/补码数的规矩进行识别。

对于非2的幂次方的乘数,假设是14,那么计算x*14可以重写为(x<<3)+(x<<2)+(x<<1),将1次乘法替换为3次移位和2次加法,或者是(x<<4)-(x<<1),将1次乘法替换为2次移位和1次加法。在实际情况中,选择使用移位、加法和减法的组合,还是使用一条乘法指令,取决于这些指令的相对速度,而这些是与机器高度相关的。大多数编译器只在需要少量移位、加法和减法就足够的时候才使用这种优化。

2.3.6 除以2的幂

在大多机器上,整数除法要比整数乘法更慢,需要30个或者更多的时钟周期。除以2的幂也可以用移位运算来实现,只不过我们用的是右移,而不是左移。无符号和补码数分别使用逻辑移位和算术移位来达到目的。

整数除法总是舍入到零。为了准确进行定义,我们要引入一些符号。对于任何实数a,定义L a 」为唯一的整数a',使得a'≤a<a'+1。例如, L3.14」=3, L-3.14」=-4 而L3 」=3 。同样,定义「al为唯一的整数a',使得a' -1<a≤a' 。例如,「3.14|=4, 「— 3.141| =-3,而「3|=3 。对于x≥0 和y>0 , 结果会是Lx/y」,而对于x<0 和y>0, 结果是「x/y| 。也就是说,对于正值向下取整对于负值向上取整。

对于无符号运算使用移位很简单,因为无符号数的右移必定是逻辑右移。如果x除以2的k次幂,那么就把x向右逻辑移动k位,向下取整。

对于补码运算,如果x除以2的k次幂,把x向右算术移动k位,向下取整。如果出现需要舍入的情况,对于正数是ok的,对于负数,就会有些问题,因为把原本的向上取整变成了向下取整。那么怎么解决这个问题呢?答案是在移位之前给这个值施加一个偏执bias,对这个值修正一下。这个偏执bias该是多少呢?答案是(1<<k)-1,也就是说对于x,在补码移位之前,需要(x+(1<<k)-1),再算数右移k,把结果向下取整,就没刚才的问题了。

总的来说,对于补码的除法,有:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值