因此,在中学数学乃至大学中,我们都学会了如何使用三角函数,它们的作用以及所解决的问题类型。但是它们始终以黑匣子的形式呈现给我。如果您需要某些东西的正弦或余弦,请按一下计算器上的sin或cos按钮,然后进行设置。没关系
我想知道的是通常如何实现三角函数。
因此,在中学数学乃至大学中,我们都学会了如何使用三角函数,它们的作用以及所解决的问题类型。但是它们始终以黑匣子的形式呈现给我。如果您需要某些东西的正弦或余弦,请按一下计算器上的sin或cos按钮,然后进行设置。没关系
我想知道的是通常如何实现三角函数。
Answers:
首先,您必须进行某种范围的缩小。触发函数是周期性的,因此您需要将参数减少到标准间隔。对于初学者,您可以将角度减小到0到360度之间。但是,通过使用一些身份,您意识到可以少花钱。如果您为0到45度之间的角度计算正弦和余弦,则可以引导您的方法来计算所有角度的所有触发函数。
减少论点后,大多数芯片都会使用CORDIC算法来计算正弦和余弦。您可能会听到人们说计算机使用泰勒级数。这听起来很合理,但事实并非如此。CORDIC算法更适合高效的硬件实现。(软件库可能在不支持触发功能的硬件上使用泰勒级数。)可能会有一些额外的处理,使用CORDIC算法可获得相当好的答案,但随后可以做一些其他事情以提高准确性。
上面有一些改进。例如,对于很小的角度theta(以弧度为单位),sin(theta)= theta等于您拥有的所有精度,因此,简单地返回theta比使用其他算法更有效。因此,在实践中有很多特殊情况的逻辑可以挤出所有可能的性能和准确性。市场较小的芯片可能不会花太多精力进行优化。
编辑:杰克·甘斯勒(Jack Ganssle)在其有关嵌入式系统的书“固件手册”中进行了不错的讨论。
仅供参考:如果您有准确性和性能方面的限制,则不应将泰勒级数用于近似数值目的的函数。(将它们保存在您的微积分课程中。)它们在单个点上利用函数的解析性,例如,所有函数的派生都存在于该点。他们不一定会在兴趣区间内收敛。他们常常为了分配函数近似值的准确性而做得很差劲,以便在评估点附近“完美”。当您远离错误时,错误通常会向上放大。而且,如果您具有任何不连续导数的函数(例如方波,三角波及其积分),泰勒级数将给您错误的答案。
当使用最大次数N的多项式在区间x0 <x <x1上近似给定函数f(x)时,最好的“简单”解法来自Chebyshev近似;请参阅数字食谱,以获取很好的讨论。请注意,我链接到的Wolfram文章中的Tj(x)和Tk(x)使用了余弦和反余弦,它们是多项式,实际上,您可以使用递归公式来获取系数。同样,请参见数字食谱。
编辑:维基百科上有一篇关于近似理论的半体面文章。他们引用的来源之一(Hart,“计算机近似值”)已经绝版了(使用过的副本往往很昂贵),但是却涉及到很多类似的细节。(Jack Ganssle在他的时事通讯The Embedded Muse的第39期中提到了这一点。)
编辑2:这是针对sin(x)的Taylor vs. Chebyshev的一些明显的误差指标(见下文)。需要注意的重要事项:
别误会:泰勒级数将在正弦/余弦中正常工作(在-pi / 2到+ pi / 2的范围内具有合理的精度;从技术上讲,有了足够的术语,您可以为所有实际输入达到所需的精度,但请尝试使用泰勒级数计算cos(100),除非使用任意精度算术,否则您将无法做到这一点。如果使用非科学计算器将我困在荒岛上,并且需要计算正弦和余弦,由于系数容易记住,因此我可能会使用泰勒级数。但是,现实世界中必须编写自己的sin()或cos()函数的应用程序非常罕见,以至于最好使用有效的实现来达到所需的精度,而泰勒级数则并非如此。
范围= -pi / 2至+ pi / 2,度5(3个条件)
范围= -pi / 2至+ pi / 2,度7(4个术语)
范围= -pi / 4至+ pi / 4,度3(2个术语)
范围= -pi / 4至+ pi / 4,5级(3个术语)
范围= -pi / 4至+ pi / 4,等级7(4个术语)
查看有关触发功能的Wikipedia文章。学习如何在代码中实际实现它们的一个好地方是数值食谱。
我不是数学家,但是我对sin,cos和tan从何而来的理解是,从某种意义上讲,当您处理直角三角形时,它们是观察到的。如果对一堆不同的直角三角形的边长进行测量,然后在图中绘制点,则可以得出正弦,余弦和正切。正如哈珀·谢尔比(Harper Shelby)所指出的那样,这些函数被简单地定义为直角三角形的属性。
通过了解这些比率与圆的几何形状之间的关系,可以获得更复杂的理解,从而得出弧度和所有优点。维基百科条目中全都有。
我想扩展@Jason S提供的答案。使用类似于@Jason S描述的域细分方法,并使用Maclaurin级数逼近,tan(),sin()的平均(2-3)X加速,通过-O3优化内置到gcc编译器中的,cos(),atan(),asin()和acos()函数得以实现。下文所述的最佳Maclaurin系列逼近函数实现了双精度精度。
对于tan(),sin()和cos()函数,为简单起见,将0到2pi + pi / 80的重叠域划分为81个等间隔,其“锚点”位于pi / 80、3pi / 80, ...,161pi / 80。然后评估和存储这81个锚点的tan(),sin()和cos()。借助触发身份,为每个触发功能开发了一个Maclaurin系列功能。±无限大之间的任何角度都可以提交给trig逼近函数,因为函数首先将输入角度转换为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.执行指示的功能或执行十亿次的时间(以秒为单位)。通过从表1的其余行中减去评估表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#()表示同时评估了正弦和余弦。同样,ASINCOS#()表示同时评估了asin和acos。同时评估两个数量几乎没有额外的开销。
结果表明,增加术语数量会稍微增加执行时间,这是可以预期的。除了tan()近似值接近±无穷大附近的位置以外,即使是最少数量的项也可以在任何地方提供约12-14位的精度。人们甚至会期望tan()函数在那里出现问题。
在Unix高端MacBook Pro笔记本电脑和Linux高端台式机上也获得了类似的结果。