Python:math.sqrt()的奇怪舍入行为

时间:2016-04-17 21:26:32

标签: python python-2.7 floating-point rounding-error

使用Python 2.7.10,我偶然发现5 * math.sqrt(3)和math.sqrt(5 ** 2 * 3)不是同一个浮点数:

import math
import decimal

print decimal.Decimal(5*math.sqrt(3))
print decimal.Decimal(math.sqrt(5**2*3))
print 5*math.sqrt(3) == math.sqrt(5**2*3)

返回

8.660254037844385521793810767121613025665283203125
8.6602540378443872981506501673720777034759521484375
False

表示它们在第15个小数位上有所不同。有趣的是,对于相邻5和3的数字,这不会发生。下面的代码显示了相等失败的几对数字:

for j in range(1,10+1):
    for i in range(1,10+1):
        a = i*math.sqrt(j)
        b = math.sqrt(i**2*j)
        if not(a == b):
            print [i,j],

有问题的[i,j]对列表包括:[3,2],[6,2],[9,2],[5,3],[9,3],[10,3] ,[3,6],[6,6],[7,6],[3,8],[6,8],[9,8],[5,10],[7,10],[ 10,10] ......关于为什么圆角破裂的原因,以及为什么精确地为这些对而不是其他对呢?

1 个答案:

答案 0 :(得分:2)

这是因为浮点运算很棘手。你的结果都不是真的正确。它们因浮点而具有舍入问题,并且它看起来很奇怪,因为它没有舍入10的幂而是2的幂。

如果需要任意精度算术,可以像下面这样使用mpmath模块:

from mpmath import *

mp.dps=50
mp.pretty = True
sqrt3 = fmul(5, mp.sqrt(3))
sqrt75 = mp.sqrt(fmul(power(5,2), 3))
print "5*sqrt(3) =    ", sqrt3
print "sqrt(5**2*3) = ", sqrt75

这给出了:

5*sqrt(3)    =  8.6602540378443864676372317075293618347140262690519
sqrt(5**2*3) =  8.6602540378443864676372317075293618347140262690519

The link provided by Rad Lexus很好地阅读了这个主题。