英特尔主流的更快但不太准确的fsin?

时间:2014-05-23 20:31:52

标签: c++ c assembly intel trigonometry

由于用于计算x86下fsin函数的函数sin(x)可以追溯到Pentium时代,显然它甚至没有使用SSE寄存器,我想知道是否有更新的更好的计算三角函数的指令集。

我习惯用C ++编写代码并进行一些asm优化,所以任何适合从C ++开始,到C语言到asm的管道都适合我。

感谢。


我目前使用的是64位,gccclang(即使是强硬的clang也没有提供任何与FPU相关的优化AFAIK)。

修改

  • 我已经实现了sin功能,即使std::sin开启,它通常比sse快2倍。
  • 我的功能永远不会慢于fsin,即使很难fsin通常更准确,但考虑到fsin永远不会超过sin实施,我会保留我的sin目前,我的sin也完全可移植,而fsin仅适用于x86。
  • 我需要这个用于实时计算,所以我会以精度换取速度,我认为我会精确到4-5位小数的精度。
  • 没有基于表格的方法,我没有使用它,它搞砸了缓存,使一切变慢,没有基于内存访问或查找表的算法。

2 个答案:

答案 0 :(得分:11)

如果需要近似正弦优化绝对精度超过-π...π,请使用:

x *(1 + x * x *( - 0.1661251158026961831813227851437597220432 + x * x *(8.03943560729777481878247432892823524338e-3 + x * x * -1.4941402004593877749503989396238510717e-4))

可以通过以下方式实现:

float xx = x * x;
float s = x + (x * xx) * (-0.16612511580269618f + xx * (8.0394356072977748e-3f + xx * -1.49414020045938777495e-4f));

也许optimized depending on the characteristics of your target architecture。此外,在链接的博客文章中没有注明,如果您在汇编中实现此功能,请使用FMADD指令。如果使用C或C ++实现,如果使用fmaf() C99标准函数,请确保生成FMADD。模拟版本比乘法和加法要昂贵得多,因为fmaf()所做的并不完全等同于乘法后跟加法(因此实现它就不正确)。

sin(x)与-π和π之间的上述多项式之间的差异如此:

graphpipi

多项式是优化的,以减少它与-π和π之间的sin(x)之间的差异,而不仅仅是某人认为是个好主意的东西。

如果您只需要[-1 ... 1]定义间隔,那么可以通过忽略其余部分使该多项式在该间隔上更准确。再次为此定义间隔运行the optimization algorithm会产生:

x *(1 + x * x *( - 1.666659904470566774477504230733785739156e-1 + x * x *(8.329797530524482484880881032235130379746e-3 + x * x *( - 1.928379009208489415662312713847811393721e-4)))

绝对错误图:

graph11

如果这对你来说太准确了,可以optimize a polynomial of lower degree for the same objective。那么绝对误差会更大,但你会保存乘法或两次。

答案 1 :(得分:5)

如果你没有接近(我假设你是,如果你想要击败硬件),你应该看看Nick在DevMaster上的sin实现:

http://devmaster.net/posts/9648/fast-and-accurate-sine-cosine

他有两个版本:“快速和邋”“方法”和“慢速和准确”方法。一对夫妇回复某人估计相对误差分别为12%和0.2%。我自己完成了一个实现,并在我的机器上找到了1/14和1/8硬件时间的运行时间。

希望有所帮助!

PS:如果你自己这样做,你可以重构缓慢/准确的方法,以避免乘法,并略微改善尼克的版本,但我不记得究竟如何...