在python中,对于精度要求不高的计算,你可以使用float类型,但是我们需要明白,float并不能够实现高精度计算,比如0.10 + 0.20。
>>> print(0.10 + 0.20)
0.30000000000000004
导致这一原因是因为所有数的运算在计算机中都是进行二进制计算的,十进制小数也是一样,十进制小数在进行运算时首先将十进制数转换成二进制数之后再进行运算,运算结果又转换成十进制并显示出来,在这一过程中出现了精度缺失的问题,导致0.1+0.2≠0.3(详细计算见博客)。
做精度控制有两种方式:(1)要求比较低的精度,使用round()函数或者格式化;(2)要求比较高的精度,超过17位的精度,采用decimal模块进行精度控制。
(1)要求比较低的精度
- round( )内置函数
round()不是简单的四舍五入的方式,在rou nd(num,n)中参数num为需要保留精度的数字,n表示精度位数。
round()如果只有一个数num作为参数,不指定位数n的时候,返回的是num的整数部分,而且是最靠近的整数(这点上类似四舍五入)。但是当出现.5的时候,两边的距离都一样,round()取靠近的偶数。例如:
# round(num,n)
# 不指定精度位数 n 时,返回整数;
# 类似于四舍五入,但是当 num 中出现 0.5 时, 结果会靠近偶数。
>>> round(2.78)
3
>>> round(2.49)
2
>>> round(2.50)
2
>>> round(2.51)
3
>>> round(3.50)
4
当指定取舍的小数点位数的时候,一般情况也是使用四舍五入的规则,但是碰到.5的这样情况,如果要取舍的位数前的小数是奇数,则直接舍弃,如果偶数这向上取舍。例如:
>>> round(3.4575,3)
3.458
>>> round(3.4585,3)
3.458
- 使用格式化
格式化的效果和round() 函数是一样的,但是书写格式不一样。采用一个“%”来表示,形如(“%.nf'”%num)的格式,其中n为精度的位数,f表示float浮点型数值。 例如:
>>> print('这本书的价格为%.2f元'%25.7894)
这本书的价格为25.79元
(2)要求比较高的精度
python里默认的是17位小数的精度,但是这里有一个问题,就是当我们的计算需要使用更高的精度(超过17位小数)的时候,如何做到?有两种方法,(1)使用格式化,即“%”的方式;(2)采用decimal模块,配合getcontext。
- 使用格式化
格式化可以显示,但是这样的方式不准确,后面的数字往往没有意义。例如:
>>> print('这本书的价格为%.30f元'%(1/3))
这本书的价格为0.333333333333333314829616256247元
- 使用decimal模块
decimal的精度和指数的范围可以通过Decimal的getcontex()获取。使用之前需要导入该模块。
from decimal import *
使用getcontext()函数,可以得到一片Context内容。其中prec是精度,默认是28位,可以自行设置,自行控制精度时就修改这个值;而Emax是指数最大值,是999999999;Emin是指数最小值,是-999999999。
运用实例如下:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999,
Emax=999999, capitals=1, clamp=0, flags=[],
traps=[InvalidOperation, DivisionByZero, Overflow])
>>> getcontext().prec = 50
>>> Decimal(1)/Decimal(3)
Decimal('0.33333333333333333333333333333333333333333333333333')
>>> Decimal(1/3)
Decimal('0.333333333333333314829616256247390992939472198486328125')
>>>