挖掘计算机中浮点数计算不精确的原理

164 阅读1分钟

引言

在平常开发过程中,我们在计算浮点数的时候,会出现不符合数学常识的情况产生,例如 0.1+0.2 != 0.3 。为什么会出现这种反直觉现象? 今天我们就来深挖一下。

整数表示

由百度可以知道,所有十进制的整数都可以用 2n2^n 的累加来进行表示,比如

7=20+21+227 = 2^0+2^1+2^2

用累计符号表示为

i=022n\sum_{i=0}^2 2^n

通式为

i=0n2n\sum_{i=0}^n2^n

小数表示

而在小数中,是用 2n2^{-n} 的累加来进行表示,如用二进制表示0.75,

0.75=21+220.75 = 2^{-1} + 2^{-2}

用累计符号表示为

i=022n\sum_{i=0}^22^{-n}

通式为

i=0n2n\sum_{i=0}^n2^{-n}

等比数列推理

我们以 212^{-1} 为首项,212^{-1}为因子构造出一个等比数列。

21222324.....2^{-1} \qquad 2^{-2} \qquad 2^{-3} \qquad 2^{-4} \qquad.....

对这个等比数列求和,恰好就是小数的表示方式,即符合

i=0n2n\sum_{i=0}^n2^{-n}

由百度,我们可以知道等比数列的求和公式为:

Sn=a1(1qn)(1q)S_n = a_1 \frac{(1-q^n)}{(1-q)}

代入到这个等比数列,可以得出

Sn=21 × 12n121S_n = 2^{-1} \ \times \ \frac{1- 2^{-n}}{1- 2^{-1}}

通过计算,我们可以算出n的值为

n=log21Snn=-log_2({1-S_n})

因为当n为整数,该数列才成立。可以得出SnS_n不能代表全部的小数。如 当Sn=0.1S_n=0.1时 可以算出

n=log20.9n=-log_2{0.9}

即,当Sn=0.1S_n=0.1时,n不是一个整数,即无法用该数列的累加表示出来。

结论

通过以上分析,我们可以知道,

  1. 在二进制中,有些数是无论如何都无法准确的表示出来的,这些小数,只能是近似值。

  2. 由于计算机的所有数字都是由二进制进行表示

我们可以得出结论:

0.1+0.20.30.1+0.2 \not= 0.3

最后,我们可以大胆说出,在计算机中,浮点数的计算是不精确的!!