【问题标题】:Exact Sine/Cosine/Tangent of Various Angles [duplicate]各种角度的正弦/余弦/正切[重复]
【发布时间】:2013-04-05 12:56:25
【问题描述】:

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

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)

但是,这似乎是一种廉价的解决方法。还有其他方法吗?谢谢!

【问题讨论】:

  • 当使用浮点数的有限长度表示时,没有办法精确表示无理数。三角函数的结果通常是不合理的,因此无法在数字计算机上准确地表示它们。您所看到的是浮点数的限制,如果对于您的问题而言,值不足以接近 0,您可能需要重新考虑如何解决它。
  • 更重要的是,math.pi 不完全是 pi,所以即使 sin 是准确的,它也不会是 0
  • 这是由于浮点计算的限制。有几种方法可以解决这个问题。符号计算,适当调整精度等。如果你说你想要什么,可能会有解决方案。
  • 这就是浮点的本质,你无法绕过它。即使是 dict 查找也只适用于某些情况。例如 (52*math.pi) / 52 != math.pi

标签: python math


【解决方案1】:

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

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

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

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

【讨论】:

  • 对于大多数用例来说,这是一个很好的解决方案。如果你需要近似的数值,你可以得到它,但尽量避免这样做。
  • 这可能就是你所说的死灵法,但这不足以解决你的问题吗?: import numpy as np from math import pi def sin(x): if x/pi == int( x/pi): return 0 elif x/pi != int(x/pi): return np.sin(x)
  • @DavidM.Sousa 这不是一个很好的解决方案,因为int((11*math.pi)/math.pi) 是 10。
  • @casevh 在这种情况下,它是 10 的事实无关紧要,因为 10 或 11 都会给出 0。 int((11*math.pi)/math.pi) 实际上是 int( 10.99999999999) 这自然是 10.
【解决方案2】:

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

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

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

如果您从未阅读过What Every Computer Scientist Should Know About Floating-Point Arithmetic,那么您现在应该阅读。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2016-06-16
    相关资源
    最近更新 更多