因此,在高中数学,也可能是大学,我们学会了如何使用三角函数,他们做什么,以及他们解决了什么样的问题。但它们总是作为一个黑盒子呈现给我。如果你需要某些东西的正弦或余弦,你可以点击计算器上的sin或cos按钮然后进行设置。哪个没问题。
我想知道的是三角函数通常是如何实现的。
答案 0 :(得分:138)
首先,你必须做一些范围缩小。 Trig函数是周期性的,因此您需要将参数减少到标准间隔。对于初学者,您可以将角度减小到0到360度之间。但是通过使用一些身份,你意识到你可以少花钱。如果你计算0到45度之间角度的正弦和余弦,你可以自己计算所有角度的所有三角函数。
一旦你减少了论证,大多数芯片都使用CORDIC算法来计算正弦和余弦。你可能会听到人们说计算机使用泰勒系列。这听起来很合理,但事实并非如此。 CORDIC算法更适合高效的硬件实现。 (软件库可能会使用Taylor系列,比如说不支持trig函数的硬件。)可能会有一些额外的处理,使用CORDIC算法得到相当好的答案,但然后做其他改进准确性。
以上有一些改进。例如,对于非常小的角度theta(以弧度表示),sin(theta)= theta到你拥有的所有精度,因此简单地返回theta比使用其他算法更有效。因此在实践中有很多特殊情况逻辑可以挤出所有可能的性能和准确性。市场较小的芯片可能无法进行尽可能多的优化工作。
答案 1 :(得分:47)
编辑:Jack Ganssle在其关于嵌入式系统的书中进行了不错的讨论,"The Firmware Handbook"。
仅供参考:如果您有准确性和性能限制,泰勒系列应不用于近似函数以用于数字目的。 (将它们保存为微积分课程。)他们在单点中使用函数的analyticity,例如事实上,它的所有衍生物都存在于那一点。它们不一定会在感兴趣的区间内收敛。他们经常在分配函数逼近的准确性方面做得很糟糕,以便在评估点附近“完美”;当你离开它时,错误通常会向上放大。如果你有一个具有任何非连续导数的函数(例如方波,三角波及其积分),泰勒系列会给你错误的答案。
最佳“简单”解决方案,当使用最大度数N的多项式在x0
编辑:维基百科有一篇关于approximation theory的半篇文章。他们引用的其中一个来源(哈特,“计算机近似”)已经绝版(并且使用的副本往往很昂贵),但是关于这样的东西会详细介绍。 (Jack Ganssle在他的时事通讯第39期The Embedded Muse中提到了这一点。)
编辑2:这是针对sin(x)的Taylor与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个项)
答案 2 :(得分:14)
我认为它们是使用Taylor Series或CORDIC计算的。一些大量使用trig函数(游戏,图形)的应用程序在启动时构造了trig表,因此它们可以只查找值而不是一遍又一遍地重新计算它们。
答案 3 :(得分:6)
查看有关触发功能的the Wikipedia article。了解在代码中实际实现它们的好地方是Numerical Recipes。
我不是一个数学家,但我对sin,cos和tan“来自”的理解是,从某种意义上说,当你使用直角三角形时,它们就会被观察到。如果你测量一堆不同的直角三角形的边长,并在图上绘制点,你可以得到sin,cos和tan。正如Harper Shelby指出的那样,函数只是被定义为直角三角形的属性。
通过了解这些比率如何与圆的几何形状相关联来实现更复杂的理解,这导致弧度和所有这些优点。这就是维基百科条目中的所有内容。
答案 4 :(得分:1)
最常用于计算机,幂级数表示用于计算正弦和余弦,这些用于其他三角函数。将这些系列扩展到大约8个项将计算接近机器epsilon的精度所需的值(可以保持的最小非零浮点数)。
CORDIC方法更快,因为它在硬件上实现,但主要用于嵌入式系统而非标准计算机。
答案 5 :(得分:0)
我想扩展@Jason S提供的答案。使用类似于@Jason S描述的域细分方法,并使用Maclaurin级数逼近,tan()的平均(2-3)X加速,实现了通过-O3优化在gcc编译器中内置的sin(),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高端台式机上获得了相似的结果。
答案 6 :(得分:-5)
如果您要求对sin,cos和tan进行更实际的解释,请考虑它们与直角三角形的关系。 cos(λ)的实际数值可以通过形成直角三角形来找到,其中一个角度是λ,并且将与λ相邻的三角形边的长度除以斜边的长度。类似于罪使用相反的一边除以斜边。对于切线使用,相对侧由相邻侧分开。记住这个的经典memonic是SOHCAHTOA(发音为socatoa)。