Python浮点数¶
在编程语言中, 小数通常以浮点数的形式存储. 浮点数和定点数是相对的: 小数在存储过程中如果小数点发生移动, 就称为浮点数; 如果小数点不同, 就称为定点数.
Python中的小数有两种数学形式:
- 十进制形式
这种就是平时我们看到的小数形式, 例如0.123, 12.3, 123.0
书写时必须包含一个小数点, 否则会被Python当作整数处理.
- 指数形式
Python小数的指数形式的写法为:
aEn 或 aen
a为尾数部分, 是一个十进制数;n为指数部分, 是一个十进制整数;E或e是固定的字符, 用于分割尾数部分和指数部分. 整个表达式等价于 \(a*10^n\).Exmple:
- \(2.1E5 = 2.1*10^5\), 其中2.1是尾数, 5是指数.
- \(3.7E{-2} = 3.7*10^{-2}\), 其中3.7是尾数, -2是指数.
- \(0.5E7 = 0.5*10^7\), 其中0.5是尾数, 7是指数.
注意, 只要写成指数形式就是小数, 即使它的最终值看起来像一个整数. 例如, 14E3等价于14000, 但14E3是一个小数.
Python中只有一种小数类型, 就是float.
C语言有两种小数类型, 分别是float和double: float能容纳的小数范围较小, double能容纳的小数范围较大.
浮点数精度问题¶
Python中浮点数类型之间的运算, 其结果并不像我们想象的那样, 例如:
>>> 0.1+0.2
0.30000000000000004
>>> 0.1+0.1-0.2
0.0
>>> 0.1+0.1+0.1-0.3
5.551115123125783e-17
>>> 0.1+0.1+0.1-0.2
0.10000000000000003
为什么在计算这么简单的问题上, 计算机会出现这样的低级错误呢? 真正的原因在于十进制数和二进制数的转换.
在计算机中, 所有的数据都是以二进制形式存储的. 当我们以十进制数进行运算的时候, 计算机需要将各个十进制数转换成二进制数, 然后进行二进制间的计算.
以类似0.1这样的浮点数为例, 如果手动将其转换成二进制, 其结果为:
可以看到, 结果是无限循环的, 也就是说, 0.1转换成二进制数后, 无法精确到等于十进制数0.1. 同时, 由于计算机存储的位数是有限的, 所以如果要存储的位数超过了计算机存储位数的最大值, 其后续位数会被舍弃.
注解
这种问题不仅在Python中存在, 在所有支持浮点数运算的编程语言中都会遇到.
如果需要非常精确的结果, 可以使用decimal模块, 它实现的十进制数运算适合会计方面的应用和高精度要求的应用.
Exmaple:
import decimal
a = decimal.Decimal("10.0")
b = decimal.Decimal("3")
print(10.0/3)
print(a/b)
运行结果位:
3.3333333333333335
3.333333333333333333333333333
可以看到, 相比普通运算的结果, 使用decimal模块得到的结果更加精确.
如果decimal模块还是无法满足需求, 还可以使用fractions模块.
Example:
from fractions import Fraction
print(10/3)
print(Fraction(10, 3))
运行结果:
3.3333333333333335
10/3
可以看到, 通过fractions模块能很好地解决浮点类型数之间的运算问题.