整数的加法和乘法运算

深入理解计算机系统第二章读书笔记

    在编程入门的时候可能都知道两个正数相加的结果可能为负数,还有一个更奇怪的现象就是:x < yx - y < 0两个表达式可能会得出不一样的结果,这些神奇的结果都和计算机整数的底层表示和运算有着密切的关系。

    C 语言中有无符号数与有符号数之分,而在 Java 中只有有符号数,下面的内容还是基于 C 语言进行说明,毕竟更 C 比 Java 更接近底层嘛。

加法运算
无符号加法

    假设我们使用 w 位来表示无符号数,那么两个加数取值范围即为:0 ≤ x, y <2w,理论上它们的和的范围为:0 ≤ sum < 2w+1,因为只有 w 位表示无符号数(要把和表示出来就需要 w+1 位),所以超过 zw的部分就会造成溢出,如下图所示。

image

    对于无符号数的溢出,计算机采用的处理方式是丢掉最高位,直观的结果就是,当发生溢出了,就将采用取模运算(或者说是减去 2w),举个例子。

    只用 4 为来表示无符号数,即 w = 4,现在有 x [1001] 和 y [1100] 相加,其结果应为:[10101] ,但是没有 5 位用来表示,所以丢掉最高位的1,剩下的值为 5 [0101],也就是 21 mod 16 = 5。

    那么如何检测是否发生溢出呢?设求和结果为 s,对于加法有 x + y ≥ x 恒成立,即只要没有发生溢出,肯定有 s ≥ x。另一方面,如果确实发生溢出了,就有 s = x + y - 2w,又有 y - 2w < 0,因此 s = x + y - 2w < x。

补码加法

    和前面一样,对于两个给定范围的加数 - 2w-1 ≤ x, y ≤ 2w-1 - 1,它们的和的范围就在 - 2w ≤ sum ≤ 2w - 2。要想把整个和的范围表示出来,依旧需要 w+1 位才行,而现在只有 w 位,因此还是需要采用将溢出部分截断。

image

    可以发现,当发生正溢出时,截断的结果是从和数中减去了 2w;而当发生负溢出时,截断结果是把和数加上 2w

    那么对于补码加法如何检测溢出结果呢?通过分析可以发现,当且仅当 x > 0, y > 0,但和 s ≤ 0 时为正溢出;当且仅当 x < 0, y < 0,但 s ≥ 0 时发生负溢出。

乘法
无符号乘法

    有了前面的基础,乘法就变得简单一些了,对于溢出情况,计算机仍然采用的是求模,比如 0 ≤ x, y ≤ 2w - 1,它们乘积的范围为 0 到 22w - 2w+1 + 1 之间,这可能需要 2w 位来表示,溢出部分直接截掉,如下所示。

image

补码乘法

    对于补码,两个乘数的范围为:- 2w-1 ≤ x, y ≤ 2w-1 + 1,那么其乘积表示范围就为 - 22w-2 + 2w-1 到 22w-2 之间,补码乘法和无符号乘法基本是一样的,只是在无符号基础上多加了一步转换,即将无符号数转换为补码。

image

乘以常数

    我们知道,计算机做加减法、位级运算的速度最快(1 个指令周期),而做乘除法很慢(10 个甚至更多指令周期),平时编写的程序中常常会乘以一个常数,为了使程序运行的更快,编译器可能会帮我们做一些处理。

    首先我们考虑常数是 2 的幂。x * 21 可以表示为 x << 1,x * 22 可以表示为 x << 2,依次类推即可。

    对于不是 2 的幂的常数,比如 x * 14 可以表示为:(x<<3) + (x<<2) + (x<<1),因为 14 = 23 + 22 + 21;聪明的你可能发现 14 还有另一种表示方法,即 14 = 24 - 21,这种表示比前一种表示方法又少了运算量,所以 x * 14 还可以表示为:(x<<4) - (x<<1)

    实际上,这里有一个通用的解决方案,对于任何一个常数 K,其二进制可以表示为一组 0 和 1 交替的序列:[(0…0)(1…1)(0…0)(1…1)],14可以表示为:[(0…0)(111)(0)],考虑一组从位位置 n 到位位置 m 的连续的 1 (n ≥ m),(对于 14 有 n = 3,m = 1)可以有两种形式来计算位对乘积的影响。

image

    这个优化不是一定的,大多数编译器只在需要少量移位、加减法就足够的时候才使用这种优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Guanngxu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值