从罪中获得cos(a)的最佳方法(a)

时间:2011-11-23 18:38:06

标签: c++ floating-point trigonometry

s作为某个(未知)角度“a”的正弦值,获得“余弦”的最快方法是什么?

我知道两种不同的方式:

c = cos(asin(s));

c = sqrt(1 - s*s);

但是我不知道函数cos(),asin()和sqrt()的实现如何在速度方面相互比较。一个人比另一个人快多快?它们在现代处理器中的实现之间是否存在显着差异,例如,在x86-64和带VFP的ARM之间?最后,什么是更好的解决方案?

编辑:由于现在已经有3个不相关的答案了,让我澄清一下:我最初并没有这个角度,我所拥有的只是正弦。所以没有必要告诉我将角度旋转90度所以我将从另一个函数获得相同的值......

5 个答案:

答案 0 :(得分:8)

这是一种方式:

  

(a)^ 2 + cos (a)^ 2 = 1(毕达哥拉斯)

     

cos (a)= sqrt (1 - (a)^ 2))

你需要找出不同的象限(即cos()的符号分开)。如果您拥有的是sin()值(不同的角度可以具有相同的sin()但cos()因符号而异),这是不可能的。

正如其他人所说,查找表实际上可能是最快的。取决于您需要的精度。这几乎肯定会比你的cos(asin())版本和square root can also be optimized更快。

  • SSE和ARM-NEON有一个平方根指令,但没有触发函数。
  • x87具有平方根和sin / cos但没有反sin / cos函数。平方根比sin / cos快。

使用Visual Studio 2010,此方法的性能比我的Core i3笔记本电脑上的基于trig的版本(具有快速浮点选项)快约6倍(每次调用约20ns)。让我们看一下生成的代码:

快速浮点选项,使用平方根:

; 15   :     return sqrt(1.0 - s*s);

    movsd   xmm1, QWORD PTR __real@3ff0000000000000
    mulsd   xmm0, xmm0
    subsd   xmm1, xmm0
    sqrtsd  xmm0, xmm1

使用trig函数:

; 22   :     return cos(asin(s));
call    ___libm_sse2_asin
jmp ___libm_sse2_cos

当切换到精确浮点模式时,生成的触发代码使用不同的功能(可能是SSE优化版本牺牲精度):

fld QWORD PTR _angle_sin$[esp+esi+65600]
call    __CIasin
call    __CIcos
fstp    QWORD PTR _angle_cos$[esp+esi+65600]

答案 1 :(得分:3)

最好的方法是使用eps * sqrt(1 - s * s),其中eps为正或负1。这是最好的方式

  • 就准确性而言,,因为1 - s * s保持接近1,因此计算平方根的误差是最小的。如果你计算弧正弦的余弦可能会失去你的精度处于'近一个'的情况下(运动:1 /为什么?提示:记住罪在pi / 2时是最大的,它的衍生物消失2 /尝试它。)编辑:我讲的太快了,因为sqrt(1 - s * s)s接近一个时遇到同样的问题。
  • 就速度而言:平方根很容易(对于类似牛顿的方法有一些算术运算),但不清楚asin做了什么(可能相当昂贵),cos很可能比sqrt慢一个数量级,因此一个平方根可能比那两个超越函数调用更快。有疑问,简介(但我已准备下注一些钱)。

忘记查找表,直到你证明sqrt(1 - s * s)对你来说不够快(甚至在那里,你可以找到方法来换取速度的sqrt精度。)

答案 2 :(得分:-1)

Sin和Cos只是相同的曲线偏移半弧度(或90度),所以:

sin(a) = cos(a + pi/2)
cos(a) = sin(pi/2 - a)

pi为3.14159 ......

答案 3 :(得分:-1)

如果你的sin / cos函数需要弧度:

cos(x) === sin(x+pi/2)

如果你的sin / cos函数需要度数:

cos(x) === sin(x+90)

答案 4 :(得分:-1)

用极坐标可视化单位圆。 r = 1,θ=(角度)。那么X,Y(笛卡尔坐标)坐标系中单位圆上的任何点都是(cos(theta),sin(theta))。