The best way to get cos (a) from sin (a)

Having s as the sine of some (unknown) angle "a", what is the fastest way to get the "cosine from"?

I know two meritorious ways:

 c = cos(asin(s)); 

and

 c = sqrt(1 - s*s); 

But I do not know how the implementation of the functions cos (), asin () and sqrt () is compared with each other in terms of speed. How faster is one above the other? Are there significant differences between their implementation in modern processors, say, between x86-64 and ARM with VFP? In the end, what's the best solution?

Edit: Since there are already 3 unrelated answers, let me clarify: I do not have a starting angle, I have a sine. Therefore there is no need to tell me to rotate the angle of 90 degrees, so I get the same value from another function ...

+6
source share
5 answers

Here is 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 cos () sign separately). This is not possible if all you have is sin () (different angles may have the same sin (), but cos () is different in sign).

As other people have noted, a checklist in practice may be the fastest. Depends on what accuracy you require. It will almost certainly be faster than the version of your cos (asin ()), and the square root can also be optimized in practice.

  • SSE and ARM-NEON have a square root instruction, but no trigger functions.
  • x87 has the square root and sin / cos, but does not have the inverse sin / cos functions. The square root is faster than sin / cos.

Using Visual Studio 2010, the performance of this method is about 6 times higher than the trigger-based version (with the fast floating-point option) on my Core i3 laptop (about 20 ns per call). Let's look at the generated code:

Quick 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 trigger functions:

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

When switching to the exact floating point mode, the generated trigger code uses different functions (presumably SSE-optimized versions sacrifice accuracy):

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

The best way is to use eps * sqrt(1 - s * s) , where eps is a plus or minus one. This is the best way.

  • From the point of view of accuracy , since 1 - s * s remains close to one, and therefore the error in calculating the square root is minimal. Calculation of the cosine of the sine of the arc may lose your accuracy if you are in "exercise: 1 / why? Hint: remember that sin is maximal at pi / 2 and its derivative disappears 2 / Try it.) EDIT: I spoke too fast, since sqrt(1 - s * s) has the same problems when s is close to one.
  • In terms of speed: square rooting is easy (a few arithmetic operations for some newton-like method), but it is not clear what asin does (maybe quite expensive), cos will probably be one order of magnitude slower than sqrt , and therefore one the square root is likely to be faster than these two transcendental function calls. In doubt, the profile (but I'm ready to bet on some money).

Forget about looking for tables until you make sure sqrt(1 - s * s) not enough for you (and even there you can find ways to compromise sqrt accuracy for speed).

+3
source

Sin and Cos are just one curve offset by half radians (or 90 degrees), so:

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

pi is 3.14159 ...

-1
source

If your sin / cos functions accept radians:

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

If your sin / cos functions have a degree:

 cos(x) === sin(x+90) 
-1
source

visualize a unit circle with polar coordinates. r = 1, theta = (angle). then any point on the unit circle in X, Y (Cartesian) coordinates is equal to (cos (theta), sin (theta)).

-1
source

Source: https://habr.com/ru/post/902240/


All Articles