Having s
as sine of some (unknown) angle "a", what is the fastest way to get the "cosine of a"?
I know two obivious ways:
c = cos(asin(s));
and
c = sqrt(1 - s*s);
But I don't know how the implementation of the functions cos(), asin() and sqrt() compares to one another in regarding speed. How faster is one over another? Are there significant difference between their implementations in modern processors, say, between x86-64 and ARM with VFP? In the end, what is the better solution?
Edit: Since there are already 3 unrelated answers now, let me clarify: I don't initally have the angle, all I have is the sine. So there is no need to tell me to rotate the angle 90 degrees so I'll have the same value from the other function...
Here's one way:
sin(a)^2 + cos(a)^2 = 1 (pythagoras)
cos(a) = sqrt(1 - sin(a)^2))
You need to figure out the different quadrants (i.e. the sign of the cos() seperately). This is not possible if all you have is the sin() value (different angles can have the same sin() but cos() differs by sign).
As other people noted a lookup table may in practice be the fastest. Depends on what precision you require. This is almost certainly going to be faster than your cos(asin()) version and the square root can also be optimized in practice.
Using Visual studio 2010 the performance of this method is about 6 times faster than the trig based version (with fast floating point option) on my Core i3 laptop (about 20ns per call). Let's look at the generated code:
Fast floating point option, using square root:
; 15 : return sqrt(1.0 - s*s);
movsd xmm1, QWORD PTR __real@3ff0000000000000
mulsd xmm0, xmm0
subsd xmm1, xmm0
sqrtsd xmm0, xmm1
Using trig functions:
; 22 : return cos(asin(s));
call ___libm_sse2_asin
jmp ___libm_sse2_cos
When switching to precise floating point mode the generated trig code uses different functions (presumably the SSE optimized versions sacrifices accuracy):
fld QWORD PTR _angle_sin$[esp+esi+65600]
call __CIasin
call __CIcos
fstp QWORD PTR _angle_cos$[esp+esi+65600]
The best way is to use eps * sqrt(1 - s * s)
, where eps
is plus or minus one. It is the best way
1 - s * s
stays close to one and therefore the error in computing the square root is minimal.sqrt(1 - s * s)
has the same problems when s
is close to one.asin
does (probably quite costly), cos
is likely to be one order of magnitude slower than sqrt
, and thus one square root is likely to be quickier than those two transcendental function calls. In doubt, profile (but I'm ready to bet some money).Forget about look up tables until you have proven that sqrt(1 - s * s)
is not fast enough for you (and even there, you can find ways to trade off some sqrt
accuracy for speed).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With