math.exp(2)和math.e**2的区别

9
在编程过程中,我注意到了math.exp(2)和math.e**2的结果有所不同。如下所示,当计算e^1时,这种差异并未出现。
作为一个经验不足的程序员,我想知道为什么会出现这种差异? 我猜测这可能与四舍五入有关。Python文档说math.exp(x)返回e**x,但这似乎不完全正确。那么为什么math.exp(x)操作与math.e**x不同呢?
>>> math.exp(1)
2.718281828459045
>>> math.e**1
2.718281828459045
>>> math.exp(1)==math.e**1
True
>>> math.exp(2)
7.38905609893065
>>> math.e**2
7.3890560989306495
>>> math.exp(2)==math.e**2
False
>>> math.exp(100)
2.6881171418161356e+43
>>> math.e**100
2.6881171418161212e+43
>>> math.exp(100)==math.e**100
False

2
相关:https://dev59.com/Om_Xa4cB1Zd3GeqP1HS_#15322395 我的猜测是:math.exp是用c(甚至是硬件)实现的,因此具有略微不同的浮点行为。 - tobias_k
2
投票重新开放。这里发生的不仅仅是“浮点数不准确”的问题。特别是,正如两个答案所解释的那样,有充分的理由期望exp(x)e ** x更精确。 - Mark Dickinson
2个回答

8
由于函数实现的不同,它们之间存在差异。由于浮点数的本质,两者都不完美。 ** 操作符在floatobject.c中实现,包含许多特殊情况,但这里没有调用它们,因此最终会到达标准C pow 函数。math.pow 函数最终执行相同的操作。 exp 函数是对同名C函数的简单封装,在mathmodule.c中定义为宏。
正如发生的那样,exp更精确(两个结果匹配,在浮点数允许的精度范围内,我在bc中计算了高精度答案)。很可能是因为在pow内部,它计算传递作为第一个参数的双精度e值的扩展精度对数,该值略小于1。

根本问题在于math.e,这是一个你正在计算其次方的数字:

2.718281828459045 09079559829...

e 的真实值为

2.718281828459045 23536028747...

而当您使用pow**时,这个错误会被放大,而如果您使用exp,由于其使用的算法细节,可能不会出现这种情况(或者可能正在内部使用更高的精度值)。

2
为了我的理解:什么是bc? - 0x0B1
1
@rosie2go 这是一个针对 Unix 和 Linux 系统的任意精度命令行计算器 - 由于它是任意精度,我可以将其设置为计算 50 位数字并将结果与 Python 浮点结果进行比较。 - Random832
那么当你将整数1转换为浮点数时,它变成了0.9999999999999999468198834395860075119344401173293590545654296875? - 0x0B1
@rosie2go 不,重点是e已经变成了一个稍微小一些的数字,因此该数字的对数不等于1。而我之前列出的值是C长双精度浮点数,而不是Python浮点数。我已经编辑了我的答案以更清晰地表达。 - Random832

7

exp(x) 是在比 e**x 更低级别的层次上实现的。它本质上是libc中一个函数的包装器。该函数可能(在某些层面上)使用Taylor series展开直接计算值(或可能使用其他数学方法,我不确定)。

另一方面,e**x 将一个数字提高到幂次。这是一种完全不同的策略,在大多数情况下可能不够精确。提高数字的幂次是难以精确完成的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接