x**0.5 和 math.sqrt(x) 哪个更精确?

23 投票
9 回答
8261 浏览
提问于 2025-04-15 11:28

我最近发现,在Python中,x**.5math.sqrt(x)这两种计算方式并不总是得到相同的结果:

Python 2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)]
on win32
>>> 8885558**.5 - math.sqrt(8885558)
-4.5474735088646412e-13

在检查所有小于10的7次方的整数时,这两种方法几乎有0.1%的样本结果是不同的,而且随着数字变大,错误的大小会慢慢增加。

所以问题是,哪种方法更准确呢?

9 个回答

7

使用 decimal 可以找到更精确的平方根:

>>> import decimal
>>> decimal.getcontext().prec = 60
>>> decimal.Decimal(8885558).sqrt()
Decimal("2980.86531061032678789963529280900544861029083861907705317042")
11

其实,pow函数和math.sqrt()函数都能算出比默认的浮点数类型更精确的结果。我觉得你看到的那些误差,主要是因为浮点数运算本身的局限性,而不是这些函数不准确。而且,计算一个七位数的平方根时,差个大约10的负13次方的数值,真的算不了什么。即使是最精确的物理计算,也很少需要那么多有效数字……

另外,使用math.sqrt()的一个好处是,它更容易阅读和理解,这通常也是选择某种方式的一个好理由。

26

这两者的准确性没有高低之分,它们都在同样的程度上偏离了实际答案:

>>> (8885558**0.5)**2
8885557.9999999981
>>> sqrt(8885558)**2
8885558.0000000019

>>> 2**1023.99999999999
1.7976931348498497e+308

>>> (sqrt(2**1023.99999999999))**2
1.7976931348498495e+308
>>> ((2**1023.99999999999)**0.5)**2
1.7976931348498499e+308

>>> ((2**1023.99999999999)**0.5)**2 - 2**1023.99999999999
1.9958403095347198e+292
>>> (sqrt(2**1023.99999999999))**2 - 2**1023.99999999999
-1.9958403095347198e+292

http://mail.python.org/pipermail/python-list/2003-November/238546.html

数学模块其实是对平台上C语言库中同名数学函数的封装;math.pow() 在你需要(或者想要)和C扩展保持高度兼容时最有用,因为它调用的是C语言的pow()

__builtin__.pow() 是Python中**运算符的实现,它可以处理复杂数、无限大的整数次方,以及模幂运算(而C语言的pow()则不支持这些)。

**运算符更全面一些。math.sqrt 可能只是C语言中平方根函数的实现,这个函数可能和pow有关。

撰写回答