为什么有些漂浮物是** 2!= a * a?

时间:2018-06-01 19:57:58

标签: python floating-point ieee

$ 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

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

这里发生了什么?我知道IEEE浮动带来了大量的误解和特质(this,例如,没有回答我的问题),但我没有看到规范的哪一部分或{{1}的实现方式可能允许这样做。

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

2 个答案:

答案 0 :(得分:15)

Python依靠底层平台进行浮点运算。我假设Python的**运算符使用pow实现(在C中使用)(由user2357112确认,引用Python 2.7.15 source code)。

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

微软的pow实施众所周知并不好。因此,对于pow(a, 2),它可能返回的结果不等于a*a

答案 1 :(得分:9)

a ** 2使用浮点电源功能(就像您可以在标准C math lib中找到的那样),它可以将任何数字提升为任何功率。

a * a只是将乘以,它更适合这种情况,并且不会导致精确错误(对于整数更为正确),例如a ** 2

对于浮点a,如果你想通过使用

提升到5的幂
a * a * a * a * a

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

a ** b很大时,

b会更有趣,因为它更有效率。但精度可能不同,因为它使用浮点算法。