#include <cmath>
#include <cstdio>
int main() {
float a = std::asin(-1.f);
printf("%.10f\n", a);
return 0;
}
I ran the code above on multiple platforms using clang, g++ and Visual studio. They all gave me the same answer: -1.5707963705
If I run it on macOS using clang it gives me -1.5707962513
.
Clang on macOS is supposed to use libc++, but does macOS has its own implementation of libc++?
If I run clang --verison
I get:
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
asin
is implemented in libm
, which is part of the standard C library, not the C++ standard library. (Technically, the C++ standard library includes C library functions, but in practice both the Gnu and the LLVM C++ library implementations rely on the underlying platform math library.) The three platforms -- Linux, OS X and Windows -- each have their own implementation of the math library, so if the library function were being used, it could certainly be a different library function and the result might differ in the last bit position (which is what your test shows).
However, it is quite possible that the library function is never being called in all cases. This will depend on the compilers and the optimization options you pass them (and maybe some other options as well). Since the asin
function is part of the standard library and thus has known behaviour, it is entirely legitimate for a compiler to compute the value of std::asin(-1.0F)
at compile time, as it would for any other constant expression (like 1.0 + 1.0
, which almost any compiler will constant-fold to 2.0
at compile time).
Since you don't mention what optimization settings you are using, it's hard to tell exactly what's going on, but I did a few tests with http://gcc.godbolt.org to get a basic idea:
GCC constant folds the call to asin
without any optimisation flags, but it does not precompute the argument promotion in printf
(which converts a
to a double
in order to pass it to printf
) unless you specify at least -O1
. (Tested with GCC 8.3).
Clang (7.0) calls the standard library function unless you specify at least -O2
. However, if you explicitly call asinf
, it constant folds at -O1
. Go figure.
MSVC (v19.16) does not constant fold. It either calls a std::asin
wrapper or directly calls asinf
, depending on optimisation settings. I don't really understand what the wrapper does, and I didn't spend much time investigating.
Both GCC and Clang constant fold the expression to precisely the same binary value (0xBFF921FB60000000 as a double), which is the binary value -1.10010010000111111011011 (trailing zeros truncated).
Note that there is also a difference between the printf
implementations on the three platforms (printf
is also part of the platform C library). In theory, you could see a different decimal output from the same binary value, but since the argument to printf
is promoted to double
before printf
is called and the promotion is precisely defined and not value-altering, it is extremely unlikely that this has any impact in this particular case.
As a side note, if you really care about the seventh decimal point, use double
instead of float
. Indeed, you should only use float
in very specific applications in which precision is unimportant; the normal floating point type is double
.