为什么 math.cos(math.pi/2) 不返回零?

问题描述 投票:0回答:3

我遇到了

math.cos()
(Python 3.11.0)的一些奇怪行为:

>>> import math
>>> math.cos(math.pi)  # expected to get -1
-1.0
>>> math.cos(math.pi/2)  # expected to get 0
6.123233995736766e-17

我怀疑浮点数学可能会在其中发挥作用,但我不确定如何。如果是这样,我假设 Python 只是检查参数是否等于

math.pi/2
开始。

我找到了Jon Skeet 的这个答案,他说:

基本上,当您的输入不能表示为精确的二进制值时,您不应该期望二进制浮点运算完全正确 - pi/2 不能,因为它是非理性的。

但如果这是真的,那么

math.cos(math.pi)
也不应该起作用,因为它也使用了
math.pi
近似值。我的问题是:为什么只有在使用
math.pi/2
时才会出现这个问题?

python floating-point trigonometry pi
3个回答
5
投票

math.pi
与 π 中的任何错误(总是有一些)在一种情况下影响很小
math.cos(math.pi)
并且在
math.cos(math.pi/2)
中非常重要。


曲线平坦

math.cos(x)
非常接近1.0时,曲线非常平坦:斜率“接近”零。大约 4700 万 浮点数
x
接近 π 的值在数学上具有
cos(x)
大于 -1.0,但它们的值比下一个可编码值 -0.99999999999999988897...

更接近 -1.0

曲线的斜率为1

x
接近 π 和
math.cos(x/2)
接近 0.0,余弦曲线有一个 |斜率 | “接近”一个。下一个较小的和下一个较大的可编码
x
都有不同的
cos(x/2)
.

结论

当|结果|

sin(x)/cos(x)
接近 1.0,many 附近
x
值将报告 1.0.

即使某些

x
值非常接近 π,这也是正确的。

对于 π 附近的

x
(如
math.pi
)和
y = |cos(x)|
,我们需要大约两倍的
y
精度才能看到
x
中的不精确性。


3
投票

math.cos(math.pi)
的结果会有类似程度的不准确,但是
-1.0 + 6e-17
不能用浮点精度表示,所以你只能得到
-1.0
。这可以这样证明:

>>> -1.0000_0000_0000_001
# -1.000000000000001
>>> -1.0000_0000_0000_0001
# -1.0

0
投票

两个原因:

  1. 我想你知道这一点,但值得重复:你没有取 π/2 的余弦。 我知道你试过了,但你没有。你取了 1.5707963267948965579989817342720925807952880859375 的余弦值,它非常接近 π/2,但不是 exactly π/2。而这个数的余弦,正如

    math.cos
    告诉你的那样,是一个接近但不完全等于0的小数。如果你能更准确地表示π/2,你可以获得更接近0的结果,但在现在在某些情况下,您不能比这更准确地表示 π/2:IEEE-754 浮点数具有有限的精度,而 1.570…375 是您能做的最好的。

  2. 在计算机编程中(就像在一般生活中一样),当你做错事时,有时你可以侥幸逃脱。当某些东西不能保证工作时,这并不意味着它一定不会工作。当你取 cos(π) 时,你得到了“幸运”,你得到了 1.0 的答案,即使在那种情况下你实际上取了 cos(3.141592653589793115997963468544185161590576171875)。 (如果你玩得更精确,你会发现 cos(3.141…875) 实际上大约是 -0.999999999999999999999999999999925,但这个数字也不可表示,四舍五入为 1.0。)

事实上,如果你深入挖掘,这些结果并不是随机的。其他答案解释了为什么,从数学上讲,即使您不能准确地表示 π 或 π/2,当取其中一个的余弦时,您可以获得比另一个更接近的结果。

© www.soinside.com 2019 - 2024. All rights reserved.