$ 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浮点数学问题,更多是**
运算符的实现问题。因此,这不仅仅是关于浮点问题(例如精度或关联性)的问题的重复。
答案 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
,如果你想通过使用
a * a * a * a * a
你最好使用a**5
因为重复乘法现在容易出现浮点积累错误,而且速度要慢得多。
a ** b
很大时, b
会更有趣,因为它更有效率。但精度可能不同,因为它使用浮点算法。