将s
作为某个(未知)角度“a”的正弦值,获得“余弦”的最快方法是什么?
我知道两种不同的方式:
c = cos(asin(s));
和
c = sqrt(1 - s*s);
但是我不知道函数cos(),asin()和sqrt()的实现如何在速度方面相互比较。一个人比另一个人快多快?它们在现代处理器中的实现之间是否存在显着差异,例如,在x86-64和带VFP的ARM之间?最后,什么是更好的解决方案?
编辑:由于现在已经有3个不相关的答案了,让我澄清一下:我最初并没有这个角度,我所拥有的只是正弦。所以没有必要告诉我将角度旋转90度所以我将从另一个函数获得相同的值......
答案 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更快。
使用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,因此计算平方根的误差是最小的。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))。