5

Unfortunately, the standard C++ library doesn't have a single call for sincos, which gives a place for this question.

First question:

If I want to calculate a sin and a cos, is it cheaper to calculate a sin and a cos, or calculate a sin then a sqrt(1-sin^2) to get the cos?

Second question:

The intel math kernel library provides very good functions for standard mathematical functions calculations, so a function vdSinCos() exists to solve the problem in a very optimized way, but the intel compiler isn't for free. Is there any open source library (C, C++, Fortran) available in linux distributions that would have those functions where I can simply link to them and have the optimum implementations?

Note: I wouldn't like to go into instruction calls, since they're not supported by all CPUs. I would like to link to a general library that would do the job for me on any CPU.

Thanks.

The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
  • You will have to measure the performance. Its the only way to know for sure. – andre Sep 13 '13 at 19:47
  • 4
    BTW: calculating `sin()` and then `cos()` via `sqrt(1-sin^2)`, as OP proposes, is numerically more stable than calculating `cos()` and then `sin()` via `sqrt(1-cos^2)`. Good that is not suggested. For small angles the difference is apparent. – chux - Reinstate Monica Sep 17 '13 at 21:25
  • 1
    @chux Are you sure that your argument won't be the opposite for angles closer to pi/2? – The Quantum Physicist Sep 18 '13 at 09:08
  • 3
    @Samer Afach Certainly. FP numbers are distributed logarithmically, not linearly else you're correct. Between 0.0 & 1.0 are as many FP numbers as between 1.0 & INF. When |x| is about DBL_EPSILON or less, Sine(x) --> x, and Cosine(x) --> 1.0. So Sine(x) as `y=sin(x)` and Cosine(x) as `sqrt(1-y*y)` yield sin, cos of `x` and `1.0`. Doing Doing Cosine(x) as `y=cos(x)` and Sine(x) as `sqrt(1-y*y)` yields sin, cos of `**0.0**` and `1.0`, a total loss of precision in sine. As x grows the issues becomes less until x is about 1.0. Number theory could follow, but this deserves its own question. – chux - Reinstate Monica Sep 18 '13 at 12:47
  • 1
    @chux I see your point. The logarithmic distribution biases the accuuracy. Thanks! – The Quantum Physicist Sep 18 '13 at 18:59
  • @chux-ReinstateMonica It looks to me like The Quantum Physicist was correct that `sqrt(1-sin^2)` is a poor approximation to `cos` near pi/2. In gnuplot: [`plot [0:1e-7] sqrt(1-sin(pi/2-x)**2), cos(pi/2-x)`](https://i.stack.imgur.com/LsUDB.png) No? You seem to be asserting otherwise, but I didn't follow your argument. – Don Hatch May 15 '22 at 14:41
  • @DonHatch Sorry not clear enough for you. In [comment](https://stackoverflow.com/questions/18793975/which-is-more-efficient-for-sines-and-cosines-sin-and-cos-or-sin-and-sqrt?noredirect=1#comment127646138_18793975) the only question I found was the terse _No?_ and was not able to discern its context clearly. – chux - Reinstate Monica May 15 '22 at 18:49
  • @chux-ReinstateMonica Sorry. What I'm trying to say is: TQP said "are you sure that your argument won't be the opposite for angles closer to pi/2"? Which seemed, to me, to imply that their impression was that `sqrt(1-sin^2)` isn't a good way to compute cos near pi/2, and I have that same impression. So I made this plot which seems to confirm our impression that `sqrt(1-sin^2)` isn't very good for arguments near pi/2, and I'm asking you if you agree. – Don Hatch May 16 '22 at 19:34
  • @DonHatch Yes. The key point is that `1-pow(sin(pi/2-x),2)` suffers severe lost of precisions for `x` near pi/2. Certainly OK for course answers, yet not of high quality. – chux - Reinstate Monica May 17 '22 at 00:35
  • @DonHatch [this](https://stackoverflow.com/questions/1527588/sin-cos-tan-and-rounding-error/46671801#46671801) may interest you as `sin(near pi)` problems are like `cos(near pi/2)`. – chux - Reinstate Monica May 17 '22 at 00:43
  • @chux-ReinstateMonica Thanks for clarifying and for the link, that's a nice writeup. So regarding the choice between `sin` and `sqrt(1-sin^2)` vs `cos` and `sqrt(1-cos^2)`, if I understand correctly, what TQP proposed earlier was exactly correct: the former is better when closer to zero, and the latter is better when closer to pi/2. – Don Hatch May 17 '22 at 07:46

3 Answers3

9

The GNU C library has a sincos() function, which will take advantage of the "FSINCOS" instruction which most modern instruction sets have. I'd say that's your best bet; it should be just as fast as the Intel library method.

If you don't do that, I'd go with the "sqrt(1-sin(x)^2)" route. In every processor architecture document I've looked at so far, the FSQRT instruction is significantly faster than the FSIN function.

Taylor Brandstetter
  • 3,523
  • 15
  • 24
1

The answer to almost every performance problem is "why don't you measure it in your code", because there are a large number of different factors that affect the performance of almost any calculation like this. For example, "Who produces the math functions". Square root is relatively simple to calculate, but I'm not convinced it's a huge difference between sqrt(1-sin*sin) and calculating cos again. What processor may also be a factor, and what other calculations are done "around" the sin/cos calculations.

I wouldn't be surprised if there is a library around somewhere that has this sort of function, but I haven't been looking.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 1
    Thanks for the answer. I want something as general as possible. A single solution for my processor isn't the answer. Isn't there a statistical answer to the question? – The Quantum Physicist Sep 13 '13 at 19:48
  • 1
    Short answer: No. Long Answer: No, because even if I prove to you that cos is faster than sqrt(1-sin^2) statistically, your code may use registers in a different way, causing more overhead, making the alternative method more beneficial... But yes, it's a good idea to test on several types and models of processors, so that you don't end up with something that is fast on Intel and slow on AMD, etc. It gets even more complex, of course, if we are talking "any processor", as the variety of possible answers suddenly increased a lot. – Mats Petersson Sep 13 '13 at 19:52
0

If precision is not critical the fastest way to get sin or cos is to use tables. Hold some global const array with sin and cos values for all agles with a step you need. So your sin/cos function just need to cast angle to index and you get the result.

Ivan Ishchenko
  • 1,468
  • 9
  • 12