三角函数是如何工作的?

114

在高中和大学数学中,我们学习如何使用三角函数、它们的作用以及解决哪些问题。但是它们总是被呈现给我一个黑盒子。如果你需要计算正弦或余弦,只需在计算器上按下相应按钮即可。这是可以的。

我想知道的是三角函数通常如何实现。


你是否对三角函数是什么或者它们如何实现感到困惑? - Kyle Cronin
17
我知道它们是什么,我知道它们的作用,我知道如何确定我需要哪个来达到什么目的。我可以向你讲述角度和距离之间的关系。我寻找的更多是类似于约翰·D·库克的答案,以及其他提到实际算法的人。 - Jurassic_C
这是一个很好的问题。例如,正弦、余弦和正切是超越函数,很难求解...另一方面,它们可以使用简单的泰勒级数展开来定义,这将为您提供所需的任何有限精度的正确答案。 - Alex
7个回答

155

首先,你需要进行一定程度的范围缩减。三角函数是周期性的,因此需要将参数缩减到标准区间内。起初,可以将角度缩减为0至360度之间。但是通过使用一些恒等式,您会意识到可以使用更少的内容来完成。如果您计算介于0和45度之间的角度的正弦和余弦,那么您可以以此为基础计算所有角度的所有三角函数。

一旦您缩减了参数,大多数芯片都使用CORDIC算法来计算正弦和余弦。你可能会听到人们说计算机使用泰勒级数。这听起来合理,但事实并非如此。CORDIC算法更适合于高效的硬件实现。(软件库可能在不支持三角函数的硬件上使用泰勒级数)。可能还有一些额外的处理,使用CORDIC算法得到相当好的答案,然后再做其他事情来提高精度。

以上还有一些优化。例如,对于非常小的角度theta(以弧度为单位),sin(theta) = theta,以你拥有的所有精度,因此直接返回theta比使用其他算法更有效率。因此,在实践中,有很多特殊情况的逻辑来挤出尽可能多的性能和精度。市场较小的芯片可能不会付出太多的优化工作。


4
很好的回答 - 尽管CORDIC本身实际上不需要范围缩减(事实上它本质上是一种范围缩减算法);对于-π/2到+π/2之间的角度,它可以很好地工作,因此你只需要对超出该范围的角度进行180度向量旋转即可。 - Jason S
4
使用多项式逼近的实现可能经常使用泰勒级数,但通常应该使用已用 Remez 算法确定的系数。http://lolengine.net/blog/2011/12/21/better-function-approximations - Pascal Cuoq
1
请注意,CORDIC使用的值表必须预先计算。因此,在“编译时”仍可以使用Taylor。 - Rhubbarb
3
这个回答似乎与这个类似问题的高评价被采纳的回答相矛盾:https://dev59.com/gXE95IYBdhLWcg3wf-AF。这个回答说sin()函数主要是在硬件级别上实现的,而另一个回答则说是在C中实现的。 - Perry
@Fortran 不确定为什么你在向我发表那条评论;这个答案和维基百科的评论都是其他人写的。如果你的问题是关于维基百科内容的,你可以在维基百科讨论页面上提问。 - Jason S
显示剩余2条评论

49

编辑:Jack Ganssle在他的嵌入式系统书籍"The Firmware Handbook"中有一个不错的讨论。

FYI:如果您有精度和性能限制,泰勒级数不应该用于近似数值目的的函数。(请将它们保留到您的微积分课程中。)它们利用了函数在单个点处的analyticity,例如该点上所有导数都存在的事实。它们不一定在感兴趣的区间内收敛。通常,它们在分配函数近似的准确性方面做得很差,以便在评估点附近“完美”;随着你离开这个点,误差通常会急剧上升。而且,如果您有任何非连续导数的函数(例如方波、三角波及其积分),泰勒级数将给出错误的答案。

最好的“简单”解决方案是,在使用最大次数为N的多项式来近似给定函数f(x)的区间x0<x<x1时,使用Chebyshev approximation;请参见Numerical Recipes中的良好讨论。请注意,我链接到的Wolfram文章中的Tj(x)和Tk(x)使用余弦和反余弦,这些都是多项式,在实践中,您使用递归公式来获得系数。再次参见Numerical Recipes。

编辑:维基百科有一篇关于逼近论的文章。他们引用的一些来源(Hart,“计算机逼近”)已经绝版了(并且二手拷贝往往很昂贵),但详细介绍了这方面的内容。(Jack Ganssle在他的通讯The Embedded Muse第39期中提到了这一点。)

编辑2:这里是sin(x)的Taylor和Chebyshev逼近的一些具体误差指标(见下文)。需要注意以下几点:

  1. 在给定范围内,Taylor级数逼近的最大误差要比同阶Chebyshev逼近的最大误差大得多。(对于大致相同的误差,使用Chebyshev可以少用一个项,这意味着更快的性能)
  2. 范围缩小是一个巨大的优势。这是因为当逼近的区间更小时,更高阶多项式的贡献会缩小。
  3. 如果无法进行范围缩小,则需要以更高精度存储系数。
请注意:泰勒级数对于正弦/余弦函数的计算是有效的(在范围为-pi/2到+pi/2的情况下具有合理的精度;从技术上讲,使用足够多的项,您可以达到任何实数输入的所需精度,但尝试使用泰勒级数计算cos(100),除非您使用任意精度算法,否则无法完成)。如果我被困在一个没有科学计算器的荒岛上,需要计算正弦和余弦,我可能会使用泰勒级数,因为系数很容易记住。但是,编写自己的sin()或cos()函数的真实世界应用程序很少,最好使用高效的实现来达到所需的精度--而泰勒级数不是最佳选择。

范围=-pi/2到+pi/2,度数5(3项)

  • 泰勒:最大误差约为4.5e-3,f(x)=x-x3/6+x5/120
  • Chebyshev:最大误差约为7e-5,f(x)=0.9996949x-0.1656700x3+0.0075134x5

范围=-pi/2到+pi/2,度数7(4项)

  • Taylor:最大误差约为1.5e-4,f(x) = x-x3/6+x5/120-x7/5040
  • Chebyshev:最大误差约为6e-7,f(x) = 0.99999660x-0.16664824x3+0.00830629x5-0.00018363x7

范围 = -pi/4 到 +pi/4,度数为3(2项)

  • Taylor:最大误差约为2.5e-3,f(x) = x-x3/6
  • Chebyshev:最大误差约为1.5e-4,f(x) = 0.999x-0.1603x3

范围 = -pi/4 到 +pi/4,度数为5(3项)

  • Taylor:最大误差约为3.5e-5,f(x) = x-x3/6+x5
  • Chebyshev:最大误差约为6e-7,f(x) = 0.999995x-0.1666016x3+0.0081215x5

范围 = -pi/4 到 +pi/4,度数为7(4项)

  • Taylor:最大误差约为3e-7,f(x)=x-x3/6+x5/120-x7/5040
  • Chebyshev:最大误差约为1.2e-9,f(x)=0.999999986x-0.166666367x3+0.008331584x5-0.000194621x7

2
这个评论是错的。每种近似方式都有其适用的时间和场合。如果你对于任何级数近似的收敛区域没有足够的分析知识来确定,那么你就不应该使用它。这适用于泰勒、切比雪夫、帕德等级数。泰勒级数通常已经足够好了。 - kquinn
4
我不知道你是否和我一样,从未对在一个小区域内评估一个函数感兴趣。即使是在一个区间上进行快速的最小二乘拟合也非常容易。那些使用泰勒级数的人只是没有抓住重点。 - Jason S
2
点赞是因为回答者知道 Hart 的存在。:smile: Hart 在这里是经典参考,即使我在25年前购买(印刷版)时很难找到。它物有所值。尽可能进行范围缩减,并结合适当的近似方法,如 Pade、Chebychev,甚至适当的 Taylor 级数,是一个不错的方法。但通常情况下,Pade 或 Chebychev 近似是优于 Taylor 级数的选择。 - user85109
1
@dotancohen:那样做就错了:对于给定的精度,切比雪夫级数需要比泰勒级数更低阶的多项式。 - Jason S
3
有什么不同吗?从-2π到+2π使用17阶泰勒级数计算sin(x)可能会被7阶或9阶切比雪夫多项式超越。如果砍树时有时间限制,用手锯可能会有问题。用电锯会更好,这个说法我没有任何问题。也许我应该把“不应该”改成“我不建议使用泰勒级数”。当然,在某些情况下你可以使用泰勒级数,但精度和性能会有问题。这里的性能指的是CPU执行时间。 - Jason S
显示剩余8条评论

14

我认为它们是使用泰勒级数CORDIC计算的。一些需要大量使用三角函数(游戏、图形)的应用程序在启动时构建三角表,以便可以直接查找值,而不必一遍又一遍地重新计算它们。


6

查看维基百科文章以了解三角函数。学习实际在代码中实现它们的好地方是Numerical Recipes

我不是很懂数学,但我对sin、cos和tan“来自”哪里的理解是,它们在处理直角三角形时被观察到。如果你测量一堆不同直角三角形的边长,并将这些点绘制在图表上,就可以得出sin、cos和tan。正如Harper Shelby所指出的那样,这些函数仅仅是直角三角形的属性。

通过了解这些比率与圆形几何的关系,可以获得更复杂的理解,从而导致弧度和所有相关知识的理解。维基百科中都有。


2

对于计算机而言,幂级数表示法最常用于计算正弦和余弦,并且这些函数也用于其他三角函数的计算。将这些级数展开到大约8项即可计算出所需的值,精度接近于机器epsilon(可以保存的最小非零浮点数)。

CORDIC方法更快,因为它是在硬件上实现的,但主要用于嵌入式系统而不是标准计算机。


1
我想扩展@Jason S提供的答案。使用类似于@Jason S所描述的域细分方法,并使用Maclaurin级数逼近,可以在gcc编译器中使用-O3优化构建的tan(),sin(),cos(),atan(),asin()和acos()函数上实现平均(2-3)倍的加速。下面描述的最佳Maclaurin级数逼近函数实现了双精度精度。

对于tan(),sin()和cos()函数,为了简单起见,将重叠的0到2pi + pi / 80域分成81个相等的间隔,其中“锚点”位于pi / 80,3pi / 80,...,161pi / 80。然后计算并存储这些81个锚点的tan(),sin()和cos()。借助三角恒等式,为每个三角函数开发了单个Maclaurin级数函数。任何±无穷大之间的角度都可以提交给三角逼近函数,因为函数首先将输入角度转换为0到2pi域。此翻译开销包含在逼近开销中。

类似的方法也被开发用于atan()、asin()和acos()函数,其中一个重叠的-1.0到1.1域被分成21个相等的间隔,锚点分别为-19/20、-17/20、...、19/20、21/20。然后只存储这21个锚点的atan()值。再次利用反三角恒等式,为atan()函数开发了一个单一的Maclaurin级数函数。然后使用atan()函数的结果来近似asin()和acos()。

由于所有反三角近似函数都基于atan()近似函数,因此允许任何双精度参数输入值。但是,asin()和acos()近似函数的参数输入被截断为±1域,因为任何超出该域的值都是无意义的。

为了测试近似函数,强制评估了十亿个随机函数评估(即,不允许-O3优化编译器绕过评估某些计算结果不会被使用的内容)。为了消除评估十亿个随机数并处理结果的偏差,首先执行了一次没有评估任何三角或反三角函数的运行成本。然后从每个测试中减去这个偏差,以获得更具代表性的实际函数评估时间的近似值。

表2. 执行指定函数或函数10亿次所花费的时间(以秒为单位)。这些估计值是通过从表1的第一行显示的评估10亿个随机数的时间成本中减去表1中其余行得到的。

tan()所花费的时间:18.0515 18.2545

TAN3()所花费的时间:5.93853 6.02349

TAN4()所花费的时间:6.72216 6.99134

sin()和cos()所花费的时间:19.4052 19.4311

SINCOS3()所花费的时间:7.85564 7.92844

SINCOS4()所花费的时间:9.36672 9.57946

atan()所花费的时间:15.7160 15.6599

ATAN1()所花费的时间:6.47800 6.55230

ATAN2()所花费的时间:7.26730 7.24885

ATAN3()所花费的时间:8.15299 8.21284

asin()和acos()所花费的时间:36.8833 36.9496

ASINCOS1()所花费的时间:10.1655 9.78479

ASINCOS2()所花费的时间:10.6236 10.6000

ASINCOS3()所花费的时间:12.8430 12.0707

(为了节省空间,表格1未显示。) 表格2展示了两次独立运行每个近似函数十亿次评估的结果。第一列是第一次运行的结果,第二列是第二次运行的结果。函数名称中的数字“1”、“2”、“3”或“4”表示在Maclaurin级数函数中使用的项数,以评估特定的三角或反三角近似值。SINCOS#()表示同时计算sin和cos。同样,ASINCOS#()表示同时计算asin和acos。同时计算两个量几乎没有额外的开销。

结果显示,略微增加项数会略微增加执行时间,这是可以预料的。即使是最小的项数也可以在除tan()近似值接近±无穷大的地方以外的任何地方给出约12-14位的精度。人们期望即使是tan()函数在那里也会有问题。

在 Unix 上的高端 MacBook Pro 笔记本电脑和 Linux 上的高端台式计算机上获得了类似的结果。


-6
如果你想要更深入地了解正弦、余弦和正切的物理意义,可以考虑它们与直角三角形的关系。实际的余弦值可以通过构建一个以 lambda 为角度的直角三角形,并将相邻于 lambda 的边长除以斜边长度来计算得出。对于正弦,同样使用对边长度除以斜边长度。对于正切,则使用对边长度除以邻边长度。记忆这个经典的助记符是 SOHCAHTOA(发音为 socatoa)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接