小能豆

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

py

我遇到了一些奇怪的行为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

我找到了:

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

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


阅读 22

收藏
2024-11-15

共1个答案

小能豆

你遇到的问题是浮点数表示中的典型现象。简而言之,Python使用的是二进制浮点数(通常符合IEEE 754标准),它无法精确地表示像π(pi)这样的无理数或它的分数(例如π/2)。由于π和π/2不能被精确表示,所有涉及这些数的计算都会引入微小的误差。

为什么 math.cos(math.pi) 没问题,但 math.cos(math.pi / 2) 有问题?

  1. math.cos(math.pi):
  2. math.pi 是一个近似值,其值为 3.141592653589793。尽管π是一个无理数,但它在计算机中被近似为一个有限的二进制值。
  3. 计算 cos(math.pi) 会使用这个近似值 3.141592653589793,它的误差非常小,在计算 math.cos(math.pi) 时,由于 cos(π) 的值恰好是 -1,这个微小的误差不会对最终结果产生显著影响,输出就是 -1.0

  4. math.cos(math.pi / 2):

  5. math.pi / 2 的值是 1.5707963267948966,但是 1.5707963267948966 在计算机中也只是一个近似值。它不能完美地表示 π/2,所以计算 cos(π / 2) 时,微小的表示误差积累并影响了结果。
  6. 由于浮点数的局限性,math.cos(math.pi / 2) 输出的是一个非常接近零的数 6.123233995736766e-17,这个值实际上就是接近于0的浮动误差。

为什么会有这样的差异?

  • 由于 cos(π) 在计算上具有特定的数学性质(即它正好是 -1),即使有微小的浮点误差,最终结果不会受到太大影响。对于 cos(π / 2),尽管期望结果是 0,但由于浮点数的不可精确性,它返回的是一个接近于零的非常小的数值 6.123233995736766e-17

浮点数精度问题

这个现象是由于浮点数的表示方式造成的。计算机中的浮点数采用二进制表示,但许多常见的十进制数(例如 π 或 π/2)在二进制中无法精确表示。计算机只能近似这些数值,这就导致了精度问题。

解决方案

对于这类问题,如果你希望计算时能够忽略这类微小的误差,可以使用 容忍误差的比较,比如:

import math

# 浮动容忍误差的检查
epsilon = 1e-15

# math.cos(math.pi/2) 近似为 0,但它非常接近于 0
if abs(math.cos(math.pi / 2)) < epsilon:
    print("Cosine of pi/2 is effectively 0")
else:
    print("Cosine of pi/2 is not 0")

通过这种方式,你可以忽略浮动误差,并判断 cos(π/2) 是否接近于零。

总结来说,math.cos(math.pi) 没有问题是因为 math.pi 的近似值和 cos(π) 的数学结果非常匹配,而 math.cos(math.pi / 2) 的小误差由于浮点数表示的限制被放大了,最终导致返回了一个非常小但不为零的数值。

2024-11-15