我想扩展@Jason S 提供的答案。使用类似于@Jason S 描述的域细分方法并使用 Maclaurin 级数近似,平均 (2-3)X 加速比 tan(), sin()、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 的高端台式计算机上获得了类似的结果。