Python 浮点数运算

浮点数用来存储计算机中的小数,与现实世界中的十进制小数不一样的是,浮点数经过二进制的形式来表示一个小数。在深刻了解浮点数的实现以前,先来看几个 Python 浮点数计算有意思的例子:python

0.1 == 0.10000000000000000000001
True
0.1+0.1+0.1 == 0.3
False

IEEE 浮点数表示法

这些看起来违反常识的“错误”并不是 Python 的错,而是由浮点数的规则所决定的,即便放到其它语言中结果也是这样的。要理解计算机中浮点数的表示规则,先来看现实世界中十进制小数是如何表示的:code

1.234 = 1 + 1/10 + 2/100 + 3/1000

能够用下面的公式来表示:图片

$$d = \sum_{i=-n}^m10^i*d_i$$ip

其中 $d_i$ 是十进制中 0~9 的数字。而若是是一个二进制的小数:ci

1.001 = 1 + 0/2 + 0/4 + 1/8

能够用下面的公式来表示:get

$$d = \sum_{i=-n}^m2^i*d_i$$it

其中 $d_i$ 是二进制中的 0 或 1。Python 中的浮点数都是双精度的,也就说采用 64 位来表示一个小数,那这 64 位分别有多少用来表示整数部分和小数部分呢?根据 IEEE 标准,考虑到符号位,双精度表示法是这样分配的:io

$$d = s * \sum_{i=-52}^{11} 2^i*d_i$$class

也就是说用1位表示符号位,11位表示整数部分,52位表示小数部分。正如十进制中咱们没法精确表示某些分数(如10/3),浮点数中经过 d1/2 + d2/4 + ... 的方式也会出现这种状况,好比上面的例子中,十进制中简单的 0.1 就没法在二进制中精确描述,而只能经过近似表示法表示出来:import

(0.1).as_integer_ratio()
(3602879701896397, 36028797018963968)

也就是说 0.1 是经过 3602879701896397/36028797018963968 来近似表示的,很明显这样近似的表示会致使许多差距很小的数字公用相同的近似表示数,例如:

(0.10000000000000001).as_integer_ratio()
(3602879701896397, 36028797018963968)

在 Python 中全部这些能够用相同的近似数表示的数字统一采用最短有效数字来表示:

print(0.10000000000000001)
0.1

浮点数运算

既然有些浮点数是经过近似值表示的,那么在计算过程当中就很容易出现偏差,就像最开始的第二个例子同样:

a = .1 + .1 + .1
b = .3
print(a.as_integer_ratio())
print(b.as_integer_ratio())
print(a == b)
(1351079888211149, 4503599627370496)
(5404319552844595, 18014398509481984)
False

为了解决运算中的问题,IEEE 标准还指定了一个舍入规则(round),即 Python 中内置的 round 方法,咱们能够经过舍入的方式取得两个数的近似值,来判断其近似值是否相等:

round(a, 10) == round(b, 10)
True

固然这种舍入的方式并不必定是可靠的,依赖于舍入的选择的位数,位数太大,就失去了 round 的做用,过小,就会引入别的错误:

print(round(a, 17) == round(b, 17))
print(round(0.1, 1) == round(0.111, 1))
False
True

Python 中使用更精确的浮点数能够经过 decimalfractions 两个模块,从名字上也能猜到,decimal 表示完整的小数,而 fractions 经过分数的形式表示小数:

from decimal import Decimal
a = Decimal(0.1)
b = Decimal(0.1000000000000001)
c = Decimal(0.10000000000000001)
print(a)
print(b)
print(c)

a == b == c
0.1000000000000000055511151231257827021181583404541015625
0.10000000000000010269562977782697998918592929840087890625
0.1000000000000000055511151231257827021181583404541015625





False
from fractions import Fraction
f1 = Fraction(1, 10) # 0.1
print(float(f1))
f3 = Fraction(3, 10) # 0.3
print(float(f3))

print(f1 + f1 + f1 == f3)
0.1
0.3
True

总结

浮点数这些奇特的特性让咱们不得不在使用的时候格外注意,尤为是当有必定的精度要求的状况下。若是真的是对精度要求较高且须要频繁使用浮点数,建议使用更专业的 SciPy 科学计算包。


pyhub

相关文章
相关标签/搜索