108

所以在高中数学,可能还有大学,我们被教导如何使用三角函数,它们做什么,以及它们解决了什么样的问题。但它们总是作为一个黑匣子呈现给我。如果你需要某个东西的正弦或余弦,你点击计算器上的 sin 或 cos 按钮,你就可以设置了。这很好。

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

4

7 回答 7

149

首先,您必须进行某种范围缩小。Trig 函数是周期性的,因此您需要将参数减少到标准间隔。对于初学者,您可以将角度减小到 0 到 360 度之间。但是通过使用一些身份,你意识到你可以用更少的钱过日子。如果您计算 0 到 45 度之间角度的正弦和余弦,则可以引导您计算所有角度的所有三角函数。

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

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

于 2008-12-05T20:59:17.403 回答
48

编辑:Jack Ganssle 在他关于嵌入式系统的书“固件手册”中有一个不错的讨论。

仅供参考:如果您有准确性和性能限制,则不应使用泰勒级数逼近用于数值目的的函数。(将它们保存在您的微积分课程中。)它们利用函数在单个点的分析性,例如,它的所有导数都存在于该点这一事实。它们不一定会在感兴趣的区间内收敛。通常他们在分配函数逼近的准确性方面做得很糟糕,以便在评估点附近“完美”;当您远离它时,错误通常会向上放大。如果你有一个带有任何非连续导数的函数(例如方波、三角波和它们的积分),泰勒级数会给你错误的答案。

当使用最大次数 N 的多项式在区间 x0 < x < x1 上逼近给定函数 f(x) 时,最好的“简单”解决方案来自切比雪夫近似;请参阅数字食谱进行很好的讨论。请注意,我链接到的 Wolfram 文章中的 Tj(x) 和 Tk(x) 使用了 cos 和反余弦,这些是多项式,实际上您使用递归公式来获得系数。再次,请参阅数字食谱。

编辑:维基百科有一篇关于近似理论的半体面的文章。他们引用的其中一个来源(Hart,“计算机近似”)已绝版(并且使用过的副本往往很昂贵),但对此类内容进行了很多详细说明。(Jack Ganssle 在他的时事通讯The Embedded Muse 的第 39 期中提到了这一点。)

编辑 2:这是 Taylor 与 Chebyshev 的 sin(x) 的一些有形错误指标(见下文)。需要注意的一些要点:

  1. 泰勒级数逼近在给定范围内的最大误差远大于同阶切比雪夫逼近的最大误差。(对于大约相同的错误,您可以使用 Chebyshev 少一个术语,这意味着更快的性能)
  2. 范围缩小是一个巨大的胜利。这是因为当近似的间隔更小时,高阶多项式的贡献会缩小。
  3. 如果您无法摆脱范围缩减,则需要更精确地存储您的系数。

不要误会我的意思:泰勒级数适用于正弦/余弦(在 -pi/2 到 +pi/2 范围内具有合理的精度;从技术上讲,只要有足够的术语,您就可以对所有实际输入达到任何所需的精度,但是尝试使用泰勒级数计算 cos(100),除非你使用任意精度的算术,否则你不能这样做)。如果我被一个非科学计算器困在荒岛上,我需要计算正弦和余弦,我可能会使用泰勒级数,因为系数很容易记住。但是,在现实世界中必须编写自己的 sin() 或 cos() 函数的应用非常少见,因此最好使用有效的实现来达到所需的精度——泰勒级数不是

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

  • Taylor:最大误差在 4.5e-3 左右,f(x) = xx 3 /6+x 5 /120
  • Chebyshev:最大误差在 7e-5 左右,f(x) = 0.9996949x-0.1656700x 3 +0.0075134x 5

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

  • Taylor:最大误差在 1.5e-4 左右,f(x) = xx 3 /6+x 5 /120-x 7 /5040
  • Chebyshev:最大误差约为 6e-7,f(x) = 0.99999660x-0.16664824x 3 +0.00830629x 5 -0.00018363x 7

范围 = -pi/4 到 +pi/4,3 级(2 项)

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

范围 = -pi/4 到 +pi/4,5 级(3 项)

  • Taylor:最大误差在 3.5e-5 左右,f(x) = xx 3 /6+x 5
  • Chebyshev:最大误差约为 6e-7,f(x) = 0.999995x-0.1666016x 3 +0.0081215x 5

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

  • Taylor:最大误差在 3e-7 左右,f(x) = xx 3 /6+x 5 /120-x 7 /5040
  • Chebyshev:最大误差约为 1.2e-9,f(x) = 0.999999986x-0.166666367x 3 +0.008331584x 5 -0.000194621x 7
于 2008-12-27T00:39:00.610 回答
14

我相信它们是使用Taylor SeriesCORDIC计算的。一些大量使用三角函数(游戏、图形)的应用程序在启动时会构建三角表,这样它们就可以只查找值而不是一遍又一遍地重新计算它们。

于 2008-12-05T20:58:33.910 回答
6

查看有关三角函数的 Wikipedia 文章。学习在代码中实际实现它们的好地方是Numerical Recipes

我不是一个数学家,但我对 sin、cos 和 tan “从何而来”的理解是,在某种意义上,当你使用直角三角形时可以观察到它们。如果您测量一堆不同直角三角形的边长并将点绘制在图表上,您可以从中得到 sin、cos 和 tan。正如 Harper Shelby 所指出的,这些函数被简单地定义为直角三角形的属性。

通过了解这些比率与圆的几何形状之间的关系,可以获得更复杂的理解,圆的几何形状导致弧度和所有这些优点。这一切都在维基百科条目中。

于 2008-12-05T21:03:52.433 回答
1

最常用于计算机,幂级数表示用于计算正弦和余弦,这些用于其他三角函数。将这些系列扩展到大约 8 项计算所需的值以接近机器 epsilon(可以保持的最小非零浮点数)的精度。

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

于 2015-02-19T03:51:54.080 回答
1

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

对于 tan()、sin() 和 cos() 函数,为简单起见,重叠的 0 到 2pi+pi/80 域被划分为 81 个相等的间隔,“锚点”位于 pi/80、3pi/80、 ...,161pi/80。然后评估并存储这 81 个锚点的 tan()、sin() 和 cos()。在三角恒等式的帮助下,为每个三角函数开发了一个麦克劳林级数函数。±无穷大之间的任何角度都可以提交给三角函数逼近函数,因为这些函数首先将输入角度转换为 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#() 表示同时计算 sin 和 cos。同样,ASINCOS#() 表示同时评估了 asin 和 acos。同时评估这两个数量几乎没有额外的开销。

结果表明,如预期的那样,增加术语的数量会略微增加执行时间。除了 tan() 近似值接近±无穷大的地方,即使是最少数量的项也能提供大约 12-14 位的准确度。人们会认为即使是 tan() 函数也会出现问题。

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

于 2018-11-06T12:38:33.187 回答
-5

如果您要求对 sin、cos 和 tan 进行更物理的解释,请考虑它们与直角三角形的关系。cos(lambda) 的实际数值可以通过形成一个直角三角形,其中一个角为 lambda,并将与 lambda 相邻的三角形边的长度除以斜边的长度。同样,对于罪,使用对边除以斜边。对于切线,使用对边除以相邻边。记住这一点的经典记忆词是 SOHCHAHTOA(发音为 socatoa)。

于 2009-01-29T06:09:26.677 回答