首页 > 编程 > Python > 正文

python中运算过程中小数精度的控制

2019-11-10 17:07:52
字体:
来源:转载
供稿:网友

用python进行运算时,如果会出现浮点数,有时候会需要对小数精度进行控制,主要方法有以下几种:

1、round()

round()是python的内置方法, round()如果只有一个数作为参数,不指定位数的时候,返回的是一个整数,而且是最靠近的偶数整数(python2.7版本则是四舍五入,这个针对的是python3版本)。如果有两个参数则最多保留精度为第二个参数大小。

In [1]: 4 - 3.6Out[1]: 0.3999999999999999In [2]: round(4 - 3.6)Out[2]: 0.0In [3]: round(4-3.6,2)Out[3]: 0.4In [4]: round(4-3.6,5)Out[4]: 0.4In [5]: round(2.55555,3)Out[5]: 2.556In [6]: round(2.555,30)Out[6]: 2.555In [7]: round(2.5) #注意这个从python3开始是向偶数看齐,即整数部分为偶数时舍弃小数部分,为奇数时进一位Out[7]: 3.0 #python3输出为2In [8]: round(3.5)Out[8]: 4.0

python文档说明如下: round(number[, ndigits])

Return the floating point value number rounded to ndigits digits after the decimal point. If ndigits is omitted, it defaults to zero. The result is a floating point number. Values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done away from 0 (so, for example, round(0.5) is 1.0 and round(-0.5) is -1.0).NoteThe behavior of round() for floats can be surPRising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information.

2、使用格式化

In [9]: '%.2f'%3.1415926Out[9]: '3.14'In [11]: float('%.3f'%1.234567890)Out[11]: 1.235

Python默认的是17位精度,也就是小数点后16位,但是这里有一个问题,就是当我们的计算需要使用更高的精度(超过16位小数)的时候该怎么做呢?

方法1:继续像上面使用格式化

In [12]: '%.30f'%(1.0/3)Out[12]: '0.333333333333333314829616256247'

方法2:使用decimal模块,配合使用其中的getcontext

In [1]: from decimal import Decimal, getcontextIn [2]: Decimal(1) / Decimal(3)Out[2]: Decimal('0.3333333333333333333333333333')In [3]: getcontext().prec = 10In [4]: Decimal(1) / Decimal(3)Out[4]: Decimal('0.3333333333')In [5]: len(str(_))Out[5]: 12 #有2个是前面的0和小数点,所以恰好是10位In [6]: print getcontext()Context(prec=10, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[Inexact, Rounded], traps=[DivisionByZero, Overflow, InvalidOperation])

具体见:https://docs.python.org/2.7/library/decimal.html#module-decimal

原理详解部分:

我们知道,将一个小数转化为二进制表示的方式是,不断的乘2,取其中的整数部分。例如


(1) 0.625*2 = 1.25, 整数部分为1,小数部分为0.25 (2) 0.25 * 2 = 0.5 , 整数部分为0,小数部分为0.5 (3) 0.5 * 2 = 1 , 整数部分为1,小数部分为0


所以0.625的二进制表示就是0.101。

然而有些小数,例如0.4,并不能够精确的转化为二进制表示,用上面的这种方法计算:


(1) 0.4*2=0.8 整数部分为0,小数部分为0.8 (2) 0.8*2=1.6 整数部分为1,小数部分为0.6 (3) 0.6*2=1.2 整数部分为1,小数部分为0.2 (4) 0.2*2=0.4 整数部分为0,小数部分为0.4

(5) 0.4*2=0.8 整数部分为0,小数部分为0.8 (6) 0.8*2=1.6 整数部分为1,小数部分为0.6 (7) 0.6*2=1.2 整数部分为1,小数部分为0.2 ……


所以0.4转化为二进制,应该是0.0110… 这样一个无限循环小数。

计算机的内存、cpu寄存器等等这些硬件单元都是有限的,只能表示有限位数的二进制位,因此存储的二进制小数就会和实际转换而成的二进制数有一定的误差。(你可以试着将0.3转化为二进制表示,也将出现一个循环小数。)

实际上,大多数情况下,小数在计算机中是以一种类似科学计数法的形式表示的,具体的可以参考一下其他的资料。但即便如此,仍然存在误差。

浮点数是用机器上浮点数的本机双精度(64 bit)表示的。提供大约17位的精度和范围从-308到308的指数。和C语言里面的double类型相同。Python不支持32bit的单精度浮点数。所以在python中不建议直接将两个浮点数进行大小比较,或者做精确的计算,往往会得到意想不到的结果。当然,如果非要用,可以参考decimal模块的相关内容。如果程序需要精确控制区间和数字精度,可以考虑使用numpy扩展库。 另外记录个链接:http://justjavac.com/codepuzzle/2012/11/11/codepuzzle-float-who-stole-your-accuracy.html

参考:https://www.zhihu.com/question/25457573/answer/30851062


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表