Python 为什么**2!=一些花车的a*a?
我只能在Windows版的Python上复制这一点——准确地说:Python 为什么**2!=一些花车的a*a?,python,floating-point,ieee,Python,Floating Point,Ieee,我只能在Windows版的Python上复制这一点——准确地说:Python 2.7.15(v2.7.15:ca079a3ea3,2018年4月30日,16:30:26)[MSC v.1500 64位(AMD64)]在win32上。在linux2上my box安装Python(Python2.7.15(默认,2018年5月1日,20:16:04)[GCC 7.3.1 20180406])时,循环似乎没有终止,表明a**2=a*a不变量保持不变 这是怎么回事?我知道IEEE浮点数有过多的误解和特性
Python 2.7.15(v2.7.15:ca079a3ea3,2018年4月30日,16:30:26)[MSC v.1500 64位(AMD64)]在win32上
。在linux2上my box安装Python(Python2.7.15(默认,2018年5月1日,20:16:04)[GCC 7.3.1 20180406])时,循环似乎没有终止,表明a**2=a*a
不变量保持不变
这是怎么回事?我知道IEEE浮点数有过多的误解和特性(例如,没有回答我的问题),但我看不出规范的哪一部分或**
的哪种实现可能允许这样做
解决重复标记:这很可能不是直接的IEEE浮点数学问题,更可能是**
运算符的实现问题。因此,这不是一个重复的问题,这些问题只涉及精度或关联性等浮点问题。Python的浮点运算依赖于底层平台。我假设Python的**
操作符使用了pow
实现(如在C中使用的)(通过引用Python确认)
通常,pow
部分通过使用(近似)对数和指数来实现。这是必要的,因为pow
支持非整数参数。(当然,这种通用实现并不排除其域子集的专门化。)
微软的pow
实现是出了名的不好。因此,对于pow(a,2)
,它可能返回的结果不等于a*aa**2
使用浮点幂函数(类似于标准C数学库中的幂函数),该函数能够将任意数提升为任意幂
a*a
只是相乘一次,它更适合这种情况,并且不容易出现精度错误(对于整数更是如此),就像a**2
一样
对于浮点a
,如果您想通过使用
$ 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
您最好使用a**5
,因为重复乘法现在容易出现浮点累加错误,而且速度要慢得多
a**b
在b
较大时更有趣,因为它更高效。但是精度可能会有所不同,因为它使用浮点算法。使用repr
显示更多的数字,这样我们就可以确切地看到它失败的值以及失败的方式……或者,既然您已经在使用格式,那么就使用{.30}
或其他什么。这不是“浮点数学坏了”的重复。OP询问为什么a**2
没有实现为a*a
@EricPostpischil:IEEE 754要求正确四舍五入的运算不是幂运算。依赖于a**2==a*a
只会带来痛苦。欢迎来到浮点,这里没有精确的东西。认真地这类事情经常发生。我们不需要在每一个应用上都提出新问题。当浮点运算中的任何东西都像数学建议的那样工作时,这应该会让我们更加惊讶。你可以在float中看到Cpow
的用法。float\u pow
的实现当然只适用于CPython,但是如果你研究一下Jython、IronPython或PyPy,你会发现它们在Java、.NET中使用类似的函数,还有RPython。我有一种预感,至少在linux上,小整数幂是特殊情况下的。a*a,a**2,math.exp(2*math.log(a))
前两个似乎一直是相等的,而第三个经常是不同的。@PaulPanzer:这不一定表明整数幂是特殊情况下的。在一个具有完全正确四舍五入的幂、exp和log的平台上,您可能会看到完全相同的结果:math.exp(2*math.log(a))
由于中间值math.log(a)
的额外四舍五入错误,通常会出现偏差。然后,调用exp
可能会放大该错误(取决于a
的值)。一个好的pow
实现应该是做一些比exp(y*log(x))
float更复杂的事情。
不使用math.pow
函数,至少不在CPython中。然而,它们最终都使用了C stdlib中相同的pow
函数(经过一系列预检查和转换,这两个函数并不完全相同),这可能是您应该在这里说的。是的,稍微有点不准确。如果原始使用的数字足够多,即使是a*a也可能有精度错误。2.5*2.5可以,但2.123456789*2.123456789会有一些精度损失。@LorenPechtel2.5*2.5
只起作用,因为它可以用只有几位的二进制表示。请尝试2.2*2.2
(4.840000000000001
)。@jpmc26是。我特意选择了一个用浮点表示的短值,这样就不会有精度损失。
a * a * a * a * a