IEEE-754 中的舍入方法
并非所有实数都可以精确地存储为浮点数。
考虑一个以归一化浮点数形式表示的实数:x=±1.b1b2b3...bn...×2mx = \pm 1.b_1 b_2 b_3 ... b_n ... \times 2^mx=±1.b1b2b3...bn...×2m,其中 nnn 是尾数中的位数,mmm 是给定浮点数系统的指数。若 xxx 没有精确的浮点数表示,则会用最近的两个浮点数 x−x_{-}x− 或 x+x_{+}x+ 来表示。
为简化讨论,设 xxx 为一个正数。在此情形下,有:x−=1.b1b2b3...bn×2mx_{-} = 1.b_1 b_2 b_3 ... b_n \times 2^mx−=1.b1b2b3...bn×2m 和 x+=1.b1b2b3...bn×2m+0.000000...0001⏟n 位×2mx_{+} = 1.b_1 b_2 b_3 ... b_n \times 2^m + 0.\underbrace{000000...0001}_{n\text{ 位}} \times 2^mx+=1.b1b2b3...bn×2m+0.n 位000000...0001×2m ,将实数 xxx替换为附近的机器数(x−x_{-}x−或 x+x_{+}x+)的过程称为 舍入,其中涉及的误差称为 舍入误差。
IEEE-754 并未明确规定如何舍入浮点数,但有几种不同的方法:
- 向零舍入
- 向正无穷舍入
- 向上舍入
- 向下舍入
- 向最近的浮点数舍入(向上或向下,取决于哪个更近)
- 截断舍入
我们将浮点数表示为fl(x)fl(x)fl(x)。上述舍入规则可以总结如下:
xxx为正数 | xxx为负数 | |
---|---|---|
向上取整(ceil) | fl(x)=x+fl(x)=x_+fl(x)=x+ 向+∞+\infty+∞取整 | fl(x)=x−fl(x)=x_-fl(x)=x− 向000取整 |
向下取整(floor) | fl(x)=x−fl(x)=x_-fl(x)=x− 向000取整 | fl(x)=x+fl(x)=x_+fl(x)=x+ 向−∞-\infty−∞取整 |
截断舍入:fl(x)=x−fl(x) = x_{-}fl(x)=x−
舍入误差
注意,两个机器数之间的差距为:∣x+−x−∣=0.000000...0001⏟n 位×2m=ϵm×2m|x_{+} - x_{-}| = 0.\underbrace{000000...0001}_{n\text{ 位}} \times 2^m = \epsilon_m \times 2^m∣x+−x−∣=0.n 位000000...0001×2m=ϵm×2m。因此,我们可以使用机器 epsilon 来限制将实数表示为机器数时的误差。
绝对误差
∣fl(x)−x∣≤∣x+−x−∣=ϵm×2m|fl(x) - x| \le |x_{+} - x_{-}| = \epsilon_m \times 2^m∣fl(x)−x∣≤∣x+−x−∣=ϵm×2m
∣fl(x)−x∣≤ϵm×2m|fl(x) - x| \le \epsilon_m \times 2^m∣fl(x)−x∣≤ϵm×2m
相对误差:
∣fl(x)−x∣∣x∣≤ϵm×2m∣x∣\dfrac{|fl(x) - x|}{|x|} \le \dfrac{\epsilon_m \times 2^m}{|x|}∣x∣∣fl(x)−x∣≤∣x∣ϵm×2m
∣fl(x)−x∣∣x∣≤ϵm\dfrac{|fl(x) - x|}{|x|} \le \epsilon_m∣x∣∣fl(x)−x∣≤ϵm
浮点运算的数学性质
-
不一定满足结合律:(x+y)+z≠x+(y+z)(x + y) + z \neq x + (y + z)(x+y)+z=x+(y+z),因为 fl(fl(x+y)+z)≠fl(x+fl(y+z))fl(fl(x + y) + z) \neq fl(x + fl(y + z))fl(fl(x+y)+z)=fl(x+fl(y+z))。
-
不一定满足分配律:z⋅(x+y)≠z⋅x+z⋅yz \cdot (x + y) \neq z \cdot x + z \cdot yz⋅(x+y)=z⋅x+z⋅y,因为 fl(z⋅fl(x+y))≠fl(fl(z⋅x)+fl(z⋅y))fl(z \cdot fl(x + y)) \neq fl(fl(z \cdot x) + fl(z \cdot y))fl(z⋅fl(x+y))=fl(fl(z⋅x)+fl(z⋅y))。
-
不一定满足累积性:反复将一个非常小的数加到一个大数上可能没有任何效果。
浮点加法
将两个浮点数相加相对简单。基本思路是:
- 将两个数调整到相同的指数。
- 从前面开始进行小学加法,直到用完系统中的位数。
- 对结果进行舍入。
例如,为了在一个只有 3 位小数部分的浮点系统中将 a=(1.101)2×21a = (1.101)_2 \times 2^1a=(1.101)2×21 和 b=(1.001)2×2−1b = (1.001)_2 \times 2^{-1}b=(1.001)2×2−1 相加,这将如下所示:
a=1.101×21b=0.01001×21a+b=1.111×21a=1.101\times 2^1 \\b=0.01001\times 2^1\\ a+b=1.111\times 2^1a=1.101×21b=0.01001×21a+b=1.111×21
你会注意到,我们加了两个具有 4 位有效数字的数,结果也有 4 位有效数字。浮点加法中没有有效数字的损失。
浮点减法与灾难性消去
浮点减法的工作原理与加法类似。然而,当减去两个大小相近的数时,会出现问题。
例如,为了从 a=(1.1011)2×21a = (1.1011)_2 \times 2^1a=(1.1011)2×21 中减去 b=(1.1010)2×21b = (1.1010)_2 \times 2^1b=(1.1010)2×21,这将如下所示:
a=1.1011????×21b=1.1010????×21a−b=0.0001????×21a=1.1011????\times 2^1\\ b=1.1010????\times 2^1\\ a-b=0.0001????\times 2^1a=1.1011????×21b=1.1010????×21a−b=0.0001????×21
当我们对结果进行归一化时,得到 1.????×2−31.???? \times 2^{-3}1.????×2−3。没有数据可以指示缺失的数字应该是什么。尽管浮点数将存储 4 位小数部分,但它只准确到 1 位有效数字。这种有效数字的损失称为 灾难性消去。
示例
考虑函数 f(x)=x2+1−1f(x) = \sqrt{x^{2} + 1} - 1f(x)=x2+1−1。当我们在接近零的值处评估 f(x)f(x)f(x) 时,可能会由于浮点减法而遇到有效数字的损失。如果 x=10−3x = 10^{-3}x=10−3,使用五位小数算术,f(10−3)=10−6+1−1=0f(10^{-3}) = \sqrt{10^{-6} + 1} - 1 = 0f(10−3)=10−6+1−1=0。
避免有效数字损失的一种方法是消除减法:
f(x)=x2+1−1=(x2+1−1)⋅(x2+1+1)x2+1+1=x2(x2+1+1)f(x) = \sqrt{x^{2} + 1} - 1 = \dfrac{ (\sqrt{x^{2} + 1} - 1) \cdot (\sqrt{x^{2} + 1} + 1) } { \sqrt{x^{2} + 1} + 1 } = \dfrac{ x^{2} } { (\sqrt{x^{2} + 1} + 1) }f(x)=x2+1−1=x2+1+1(x2+1−1)⋅(x2+1+1)=(x2+1+1)x2
因此,对于 x=10−3x = 10^{-3}x=10−3,使用五位小数算术,f(10−3)=10−62f(10^{-3}) = \dfrac{ 10^{-6} } { 2 }f(10−3)=210−6。