22

In C library math.h, there was a sincos function which was pretty efficient, because it computed both sine and cosine in a time closer to a single call to sin() or cos() than to the total time of calling both.

Is there such function in C++ standard library?

galinette
  • 8,896
  • 2
  • 36
  • 87
  • 1
    here are a few pointers: http://stackoverflow.com/questions/2683588/what-is-the-fastest-way-to-compute-sin-and-cos-together – Pavel Jun 20 '14 at 13:19
  • Well actually I already have my own sincos SSE optimized functions, but here I'm writing an example plugin and I want to make it as simple as possible using no other library than the standard library – galinette Jun 20 '14 at 18:01
  • GCC at a low level of optimization (`-O1`) and, in general `-Ofast` will do this for you. https://godbolt.org/z/jCiTDo – alfC Dec 14 '19 at 03:34
  • 1
    I'd profile [`std::exp(I * angle)`](https://en.cppreference.com/w/cpp/numeric/complex/exp), or look at what code it generates - hopefully a (possibly internal) optimized `sincos` function. In any case, it won't be any worse than separate calls to `sin` and `cos`, and should avoid the numerical instabilities in trying to derive one from the other by trig identities. – Brett Hale Aug 07 '21 at 17:30

5 Answers5

15

Is there no such function in c++ standard library?

No, unfortunately there isn't.

In C library math.h, there was a sincos function

On Linux, it is available as GNU Extension. It's not standard in C either.

Ali
  • 56,466
  • 29
  • 168
  • 265
6

Just use sin and cos separately and turn on optimizations. C compilers are pretty good at optimizing, and they will probably realize that you are computing both the sine and cosine of the same variable. If you want to make sure, you can allways inspect the resulting assembly (for gcc use the -S option) and see what did it generate.

The compiler will probably optimize away any calls to sin or cos in favour of simply using SSE intructions to calculate it. I'm not sure SSE has a sincos opcode but even calculating them separatly is faster than calling any sincos function that the compiler won't optimize out.

Evan Dark
  • 1,311
  • 7
  • 7
  • 3
    SSE has no support for sin/cos or any "fancy" function beyond division and square root. But some compilers (such as the Intel Compiler) will have a vectorized implementation that uses SSE. – Mysticial Jun 20 '14 at 17:19
  • Are compilers really able to do high level optimizations? sin and cos are call to functions, not arithmetic operators. – galinette Jun 20 '14 at 18:00
  • 1
    SSE has no sin, cos or sincos instructions. Only base arithmetics. – galinette Jun 20 '14 at 18:02
  • @galinette: sin and cos are treated specially by the compiler and optimized out when optimizations are enabled, and yes it seems SSE has no sin or cos functions (I remembered wrong), so it's the x87 instructions of course. – Evan Dark Jun 24 '14 at 11:41
  • 5
    Using godbolt I confirmed that newer GCC versions at high optimization levels do manage to coalesce sin + cos to sincos, but clang and VS2017 have no such optimization. – Dan Olson Jun 15 '18 at 22:41
  • 1
    @DanOlson, I think MSVC 2017 and above does optimize Sine and Cosine calls: https://devblogs.microsoft.com/cppblog/msvc-code-optimizer-improvements-in-visual-studio-2017-versions-15-5-and-15-3/ – Royi Jun 03 '19 at 11:11
  • 3
    @DanOlson, confirmed here https://godbolt.org/z/wuS26Z for GCC and intel at a fairly low level of optimization. clang does the optimization only in `-Ofast` (fast-math). This hints me that `sincos` may not guarantee the *exact* same result as `sin` and `cos` called separately. – alfC Dec 14 '19 at 03:33
  • 1
    This answer is more useful than the other one. It is a pity that it was downvoted for a technical reason. I would suggest removing the controversial assertion about SSE. – alfC Dec 14 '19 at 03:59
  • As more you digg into it as more it gets complicated... I've tested various combinations on [quick-bench.com](https://quick-bench.com/q/PFBg_CCf1N4T81xxWBnXiYtC6ec). By default sin() and cos() may have _side effects_ (error codes), so they will be executed twize in the expression `x=sin(x)+sin(x);`. This behaviour is also disabled with `-Ofast`. gcc seems to disable it also in `-O3` for _sin_ and _cos_. Thus it is **14x faster** to evaluate `cos(x) * cos(x)` compared to `sin(x) * cos(x)` (gcc 10.1 with -O3). – m2j Nov 27 '20 at 13:10
4

While there is no standard C++ library function, you can define a template function pretty quickly:

template <class S>
std::pair<S,S> sincos(S arg) { return { std::sin(arg), std::cos(arg) }; }

You can then get the result on a single line (with C++ 17) with:

auto [s, c] = sincos(arg);

It's very convenient if you are doing this often, saves space, and is self-documenting, so I would highly recommend it. If you're worried about performance, don't. When compiled with optimizations, it should produce the exact same code as calling sin and cos separately. You can confirm this is the case with clang++ -std=c++17 -S -o - -c -O3 sincos.cpp on the following test code:

#include <cmath>
#include <utility>
#include <iostream>

template <class S>
std::pair<S,S> sincos(S arg) { return { std::sin(arg), std::cos(arg) }; }

void testPair(double a) {
    auto [s,c] = sincos(a);
    std::cout << s << ", " << c << '\n';
}

void testSeparate(double a) {
    double s = std::sin(a);
    double c = std::cos(a);
    std::cout << s << ", " << c << '\n';
}

On MacOS with clang, both test functions compile to the exact same assembly (minus the name changes) that call ___sincos_stret to perform the combined computation (see https://stackoverflow.com/a/19017286/973580).

ɲeuroburɳ
  • 6,990
  • 3
  • 24
  • 22
  • 1
    godbolt showing that at -O3 we get the desired assembly: https://godbolt.org/z/KdT9fjEEr – user14717 Mar 26 '22 at 22:40
  • So the compiler is smart enough to call an an optimized version if sincos when it sees them in pairs like this? @godbolt asm shows a call `sincos`, so we assume that this will be the more efficient function? That is cool if true. – wcochran Jul 28 '23 at 20:12
0

There's no such built-in standard function. Here's direct assembly code to compute sincos at once (gcc syntax)

This is only when needing 80 bit precision. There's no vectorization with x87 instructions so it won't improve the performance unless long double is needed(and it's actually using 80 bits). Even then separate sinl and cosl will be optimized to such a result as below.

It's not a good practice(neither using assembly directly or x87 in most cases) ...but it was a fun exercise so here's the result.

long double input = 5L;

long double sin = input;
long double cos = 0L;
__asm__ (
    "fldt %0;"
    "fsincos;" // sincos in one instruction
    "fstpt %1;"
    "fstpt %0;"
    : "+m" (sin), "+m" (cos)
);
printf("sin %.19Lf cos %.19Lf \n", sin, cos);
Pawel
  • 16,093
  • 5
  • 70
  • 73
-1

Instead, you can use this function which only uses std::cos and std::sqrt (haven't actually tested it, it may not work)

template <typename T>
constexpr inline static void sincos(const T &x, T* sin, T* cos) {
    (*cos) = std::cos(x);
    (*sin) = std::sqrt(static_cast<T>(1) - *cos**cos);
    if ((int)(x / M_PI) & 1) (*sin) = -(*sin);
}
  • The result of that will have poor precision at some inputs (try it with 1e-6) and is likely to be much slower than just using sin and cos. – Sneftel Jun 26 '23 at 16:25