Python:math.sqrt() 的奇怪舍入行为
Python: weird rounding behavior of math.sqrt()
使用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)
returns
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]... 关于舍入中断的原因以及为什么恰好是这些对而不是其他对的任何想法?
这是因为浮点运算很棘手。您的两个结果实际上都不正确。由于浮点数,它们存在舍入问题,而且看起来很奇怪,因为它不是按 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 是关于这个主题的好读物。
使用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)
returns
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]... 关于舍入中断的原因以及为什么恰好是这些对而不是其他对的任何想法?
这是因为浮点运算很棘手。您的两个结果实际上都不正确。由于浮点数,它们存在舍入问题,而且看起来很奇怪,因为它不是按 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 是关于这个主题的好读物。