1、无符号加法
1. 原理
如果不加限制的话,无符号加法的字节数量会不断地膨胀。所以必须采取一定的措施。我们采取的措施是把任何权重大于
2
w
−
1
2^{w-1}
2w−1的位进行截断
其结果与模运算一致
2.溢出
是指完整的整数结果不能放到数据类型的字长限制中去。检测无符号数加法的溢出的方法为
也就是无符号加法中,结果的值大于加数的值
2、补码加法
正溢出之后变成负数,负溢出之后变成正数。
3、补码的非
这里补码的非指的是补码的加法逆元。
对于TMin来说,它本身就是他的加法逆元,因为TMin + TMin将导致负溢出得到0。
求位级补码非的两种方式
- 笫一种方法是对每一位求补,再对结果加 1对于C语言来说,-x和~x+1结果相同
- 第二种方式是找到位级表示最右边的1,将这个1左边的所有位取反。
4、无符号乘法
5、补码乘法
首先我们需要知道无符号和补码乘法的位级表示是相同的
这个式子的含义是先把x*y截断,再将无符号数变成补码,如下图所示
因为截断后的位级表示是相同的,所以可以按照上面的原理进行补码乘法的计算。
6、乘以常数
由于在大多数机器上乘法指令相当缓慢,所以编译器有时会使用一项重要优化,也就是用移位和加法运算代替乘以常数因子的乘法。可以通过向左移位操作,让一个数乘以2的幂。这样做可能会导致溢出,但是溢出后的结果与正常的补码乘法结果一致。此时我们就可以用如下操作计算乘以常数。
例如对于
14
=
2
3
+
2
2
+
2
1
14 = 2^3 + 2^2 + 2^1
14=23+22+21来说,可以使用
(
x
<
<
3
)
+
(
x
<
<
2
)
+
(
x
<
<
1
)
(x<<3)+(x<<2)+(x<<1)
(x<<3)+(x<<2)+(x<<1)进行实际运算。
当然,选择使用移位、 加法和减法的组合,还是使用一条乘法指令,取决于这些指令的相对速度, 而这些是与机器高度相关的。 大多数编译器只在需要少量移位、 加法和减法就足够的时候才使用这种优化。
7、除以2的幂
整数的除法总是舍入到0的,也就是正数向下取整,负数向上取整。
7.1 无符号除法
对于无符号整数来说,除以2的幂只要执行逻辑右移也就是除以2的幂之后会向下取整
7.2 有符号除法
如果按照算术右移进行有符号除法的操作的话,其结果是向下取整, 而不是向零取整(也就是负数向上取整)
为了解决这个问题,通常采用下面的方法进行解决。
下图在第3 列,给出了 -12340 加上偏量值之后的结果,低 k位(那些会向右移出的位)以斜体表示。 我们可以看到,低 k 位左边的位可能会加 1, 也可能不会加 1。对于不需要舍 入的情况(k = 1),加上偏量只影响那些被移掉的位。 对于需要舍入的情况,加上偏量导致较高的位加 1, 所以结果会向零舍入。
现在我们看到, 除以2的幂可以通过逻辑或者算术右移来实现。这也正是为什么大多数机器上提供这两种类型的右移。不幸的是, 这种方法不能推广到除以任意常数。同乘法不同, 我们不能用除以2的幕的除法来表示除以任意常数K的除法。