std::cos produces different results in GCC and MSVC

1 week ago 3
ARTICLE AD BOX

IEEE 754 / IEC 60559, which apply to most C++ platforms, have a "correctly rounded" (i.e. max of 0.5 ULP error) requirement imposed on the basic operations, but that does not apply to trig functions.

Math functions can have more error and most implementers aim for 1.0 ULP maximum error, meaning that the final bit can differ between implementations and not be considered a bug.

Ben Voigt's user avatar

2 Comments

It's worth clarifying what those mean. 0.5 ULP means "rounded to the nearest representable value, with ties permitted to be either", and 1.0 ULP means "rounded to one of the two adjacent representable values" (which theoretically permits 3 values if the original was exact, though I'm not sure if this comes up). This is dependent on the input; sin(M_PI) is much more than 1 ULP from 0, because M_PI cannot be exactly π.

2026-03-27T18:06:22.993Z+00:00

This functions are implemented by the standard library. Since MSVC and gcc are using different standard library their implementation might be different. Both are using some approximation of this functions. In your case expected value most probably is in the middle between values which can be represented by double type and during calculation errors have accumulated in different way leading to minimal divergence between those libraries.

So this is simple rounding issue and result of using different algorithm to calculate cos.

Note there is x86 instruction FCOS, but it has so poor accuracy guaranties and so slow that compilers are using own implementations.

The Difference Between x87 Instructions FSIN, FCOS, FSINCOS, and...

The purpose of this paper is to inform users of many of the implementation details of the x87 trigonometric instructions. If users find that the x87 elementary transcendental instructions are not adequate for their needs, they should consider using the software libraries of transcendental functions available through the Intel® C++ Compiler and Intel® Fortran Compiler, the Intel® Math Kernel Library (Intel® MKL) product, or libraries from other providers. Just as double precision arithmetic is provided to users when single precision floating-point arithmetic is not adequate, so these software library functions provide more accurate approximations when the x87 instructions are not adequate.

The paper explains that FSIN(x), FCOS(x), FSINCOS(x) and FPTAN(x) are approximations of the corresponding mathematical functions of argument (x • π/p), and not of argument (x). Therefore they can only be used to approximate the mathematical functions sin(x), cos(x), and tan(x) on a limited domain, outside of which a more accurate argument reduction technique is necessary in order to contain the errors, or, alternatively, accurate software implementations of these mathematical functions may to be used.

Marek R's user avatar

3 Comments

The x87 cordic implementation of FCOS isn't all that bad - especially if you enable 64bit mantissa long double. There is a problem with range reduction when the argument x becomes large but that doesn't apply to the OP's problem above. I try to keep all my trig arguments in the range |x| <= pi. There are circumstance where using the identity cos(x) = 1- 2*sin(x)^2 can be a lot more accurate for small values of x (recurrence relations for FFT for example).

2026-03-27T18:18:03.383Z+00:00

I think there's a factor of two missing between the cos(x) and sin(x) angles?

2026-03-27T19:33:30.8Z+00:00

Yes I was in a hurry (too late to fix that typo now) should have been 2*sin(x/2)^2.

2026-03-27T20:07:55.837Z+00:00

Accuracy of floating point operations is standardized this way: https://eel.is/c++draft/basic.fundamental#12

Except as specified in [basic.extended.fp], the object and value representations and accuracy of operations of floating-point types are implementation-defined.

(emphasis mine).

Unfortunately, I see no way to enforce that different implementations give the same results.

STerliakov link is interesting in this regard, in order to get more insights. And also an academic reference and the most recent version to this day (thanks to Martin Brown).

As commented by Jesper Juhl, when dealing with floating point operations, consider that there are no such thing as strict equality: give you an expected acceptable relative or absolute error, which depend on your exact application.

Oersted's user avatar

1 Comment

Although C++ doesn't rule out platforms which are not IEEE 754 / IEC 60559 compliant, it does require platforms to indicate the level of compliance, and that standard does impose accuracy requirements on some operations.

2026-03-27T15:56:55.523Z+00:00

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Read Entire Article