我遇到了一些奇怪的行为math.cos()(Python 3.11.0):
math.cos()
>>> 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。
math.pi/2
我找到了:
基本上,当您的输入不能表示为精确的二进制值时,您不应该期望二进制浮点运算完全正确 - pi/2 不能,因为它是无理数。
但如果这是真的,那么math.cos(math.pi)也不应该起作用,因为它也使用了近似值。我的问题是:为什么这个问题只在使用math.pi时才会出现?math.pi/2
math.cos(math.pi)
math.pi
你遇到的问题是浮点数表示中的典型现象。简而言之,Python使用的是二进制浮点数(通常符合IEEE 754标准),它无法精确地表示像π(pi)这样的无理数或它的分数(例如π/2)。由于π和π/2不能被精确表示,所有涉及这些数的计算都会引入微小的误差。
math.cos(math.pi / 2)
3.141592653589793
计算 cos(math.pi) 会使用这个近似值 3.141592653589793,它的误差非常小,在计算 math.cos(math.pi) 时,由于 cos(π) 的值恰好是 -1,这个微小的误差不会对最终结果产生显著影响,输出就是 -1.0。
cos(math.pi)
cos(π)
-1
-1.0
math.cos(math.pi / 2):
math.pi / 2
1.5707963267948966
π/2
cos(π / 2)
6.123233995736766e-17
0
这个现象是由于浮点数的表示方式造成的。计算机中的浮点数采用二进制表示,但许多常见的十进制数(例如 π 或 π/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) 是否接近于零。
cos(π/2)
总结来说,math.cos(math.pi) 没有问题是因为 math.pi 的近似值和 cos(π) 的数学结果非常匹配,而 math.cos(math.pi / 2) 的小误差由于浮点数表示的限制被放大了,最终导致返回了一个非常小但不为零的数值。