2

有没有办法获得角度的确切正切/余弦/正弦(以弧度为单位)?

math.tan()//没有给出某些角度的精确值math.sin()math.cos()

>>> from math import *
>>> from decimal import Decimal
>>> sin(pi) # should be 0
1.2246467991473532e-16
>>> sin(2*pi) # should be 0
-2.4492935982947064e-16
>>> cos(pi/2) # should be 0
6.123233995736766e-17
>>> cos(3*pi/2) # 0
-1.8369701987210297e-16
>>> tan(pi/2) # invalid; tan(pi/2) is undefined
1.633123935319537e+16
>>> tan(3*pi/2) # also undefined
5443746451065123.0
>>> tan(2*pi) # 0
-2.4492935982947064e-16
>>> tan(pi) # 0
-1.2246467991473532e-16

我尝试使用 Decimal(),但这也无济于事:

>>> tan(Decimal(pi)*2)
-2.4492935982947064e-16

numpy.sin(x)其他三角函数也有同样的问题。

或者,我总是可以创建一个带有值字典的新函数,例如:

def new_sin(x):
    sin_values = {math.pi: 0, 2*math.pi: 0}
    return sin_values[x] if x in sin_values.keys() else math.sin(x)

然而,这似乎是一种廉价的绕过它的方法。还有其他方法吗?谢谢!

4

2 回答 2

9

将 pi 的准确数值存储在计算机中是不可能的。math.pi是可以存储在 Python 浮点数中的最接近 pi 的近似值。math.sin(math.pi)返回近似输入的正确结果。

为避免这种情况,您需要使用支持符号算术的库。例如,同情:

>>> from sympy import *
>>> sin(pi)
0
>>> pi
pi
>>> 

sympy 将对表示 pi 的对象进行操作,并可以给出准确的结果。

于 2013-04-12T21:16:22.780 回答
3

当您处理不精确的数字时,您需要明确地处理错误。math.pi(或numpy.pi) 不完全π是 ,例如,它是最接近 56 位的二进制有理数π。而sin那个数字的不是0

但它非常接近0。同样,tan(pi/2)它不是无穷大(或 NaN),而是巨大的,asin(1)/pi非常接近 0.5。

因此,即使算法在某种程度上是精确的,结果仍然不准确。

如果您从未阅读过关于浮点运算的每位计算机科学家都应该了解的内容,那么您现在应该阅读。

处理这个问题的方法是使用 epsilon-comparisons 而不是到处进行精确比较,并在打印出来时明确地四舍五入,等等。

使用decimal.Decimal数字而不是float数字使这更容易。首先,您可能以十进制而不是二进制来思考,因此您更容易理解错误并做出决定。其次,您可以明确设置值的精度和其他上下文信息Decimal,而float始终是 IEEE 双精度值。

正确的做法是对算法进行全面的错误分析,适当地传播错误,并在需要的地方使用该信息。简单的方法是只选择一些对您的应用程序“足够好”的显式绝对或相对 epsilon(以及无穷大的等价物),并在任何地方使用它。(您可能还希望使用适当的特定领域知识将某些值视为倍数,pi而不仅仅是原始值。)

于 2013-04-12T21:22:54.513 回答