1. 整数运算

1.1 加法

无符号加法: 考虑两个非负整数 x 和 y,满足 0<=x, y<2^w。当 x+y >= 2^w 时,和发生溢出。 溢出情况就是该和减去 2^w 的结果。

补码加法: 当 x+y 小于 -2^(w-1) 时,发生负溢出;当它大于 2^(w-1) 时,发生正溢出。负溢出导致和增加 2^w,正溢出导致和减少 2^w。

补码加法的溢出

1.2 乘法

在大多数机器上,整数乘法指令非常慢,需要 10 个或者更多的时钟周期,然而加法、减法和位运算只需要 1 个时钟周期。

左移一个整数等价于执行与 2 的幂相等的乘法。

由于整数乘法比移位和加法的代价要大得多,许多 C 语言编译器使用移位和加法运算的组合代替乘以常数因子的乘法。例如,表达式 x * 14,利用 14 = 2^3 + 2^2 + 2^1,编译器会将乘法重写为 (X << 3) + (X << 2) + (X << 1)。

1.3 除法

在大多数机器上,整数除法要比整数乘法更慢,需要 30 个或者更多的时钟周期。

除以 2 的幂可以用右移(算术右移)运算来实现。

不能用除以 2 的幂的除法来表示除以任意常数的除法。

2. 浮点数

2.1 二进制小数

小数的二进制表示法只能表示被写成 x*2^y 的数,其他数值只能近似表示。例如数字 1/5 可以用十进制小数 0.2 精确表示。但是,并不能把它准确地表示为二进制小数,我们只能近似地表示它,增加二进制表示的长度可以提高表示的精度。

2.2 IEEE 浮点表示

IEEE 754 浮点标准使用 V = (-1)^s * M * 2^E 来表示一个数:

  • 符号 s:s 决定数值是负数(s=1)还是正数(s=0)
  • 尾数 M:是个二进制小数,范围是 1-2-ε 或者 0-1-ε
  • 阶码 E:E 的作用是对浮点数加权,这个权重是 2 的 E 次幂

将浮点数的位表示划分为三个字段,分别对这些值进行编码:

  • 一个单独对符号位 s 编码符号 s
  • k 位对阶码字段 exp 编码阶码 E
  • n 位对小数字段 frac 编码尾数 M
标准浮点格式

浮点数只能近似表示实数运算,它采用向偶数舍入的方式。需要注意的是,浮点数运算不具备结合性和分配性。

总结一下:

  • 整数运算溢出会导致结果异常,编程时要格外注意整数的范围。
  • 通过左移和右移来进行整数乘除运算比算术运算要高效。
  • 浮点数采用 IEEE 754 标准表示,编码方式是符号、阶码和尾数。
  • 浮点数是近似表示的,它的运算不精确,之前总结过Java 比较浮点数的正确方式