为什么 a**2 != a * a 对于一些花车?

Why is a**2 != a * a for some floats?

$ python --version
Python 2.7.15

$ type test.py
import random

while True:
    a = random.uniform(0, 1)
    b = a ** 2
    c = a * a
    if b != c:
        print "a = {}".format(a)
        print "a ** 2 = {}".format(b)
        print "a * a = {}".format(c)
        break

$ python test.py
a = 0.145376687586
a ** 2 = 0.0211343812936
a * a = 0.0211343812936

我只能在 Python 的 Windows 版本上重现它 - 准确地说:Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32。在我 Python (Python 2.7.15 (default, May 1 2018, 20:16:04) [GCC 7.3.1 20180406] on linux2) 的 Arch Linux 盒子安装中,循环似乎没有终止,表明 a**2 = a * a 不变量在那里。

这是怎么回事?我知道 IEEE 浮点数有很多误解和特质(例如,this 没有回答我的问题),但我看不出规范的哪一部分或 [=14= 的哪种实现方式] 可能允许这样做。

解决重复标记问题:这很可能不是直接的 IEEE 浮点数学问题,而是 ** 运算符的实现问题。因此,这不是仅询问浮点问题(例如精度或关联性)的问题的重复。

Python 的浮点运算依赖于底层平台。我假设 Python 的 ** 运算符使用 pow 实现(在 C 中使用)(由 user2357112 referring to Python 2.7.15 source code 确认)。

一般来说,pow 部分是通过使用对数和指数(的近似值)来实现的。这是必要的,因为 pow 支持非整数参数。 (当然,这种通用实现并不排除对其领域子集的专业化。)

Microsoft 的 pow 实施是出了名的不好。因此,对于 pow(a, 2),它返回的结果可能不等于 a*a.

a ** 2 使用 浮点数 幂函数(就像你可以在标准 C 数学库中找到的那个),它能够将任何数字提升到任何电源。

a * a只是乘以一次,它更适合这种情况,并且不易出现精度错误,(对于整数更是如此),如a ** 2 会是。

对于浮点 a,如果你想提升到 5 的幂,使用

a * a * a * a * a

你最好用 a**5 因为重复乘法现在容易出现浮点累加错误,而且速度要慢得多。

b 很大时,

a ** b 更有趣,因为它更有效率,例如。但是精度可能会有所不同,因为它使用了浮点算法。