When optimizations cross the border of sanity
Par zogzog, mercredi 12 décembre 2018 à 16:31 :: General
I'm a bit annoyed because I have this toy program on my mac:
#include <iostream> #include <cmath> int main(int argc, char **) { float f = 1, c = 0.1f; for (int i=0; i < 45; ++i) { std::cerr << "f=" << f << " sqrt(f)=" << sqrt(f) << "\n"; f *= c; } return 0; }
It's pretty simple, and one would expect it to print numbers smaller and smaller until it prints zeroes. That's not what happens when built with clang and the fast-math option on macOS:
clang++ -O1 -ffast-math t.cc && ./a.out f=1 sqrt(f)=1 f=0.1 sqrt(f)=0.316228 f=0.01 sqrt(f)=0.1 f=0.001 sqrt(f)=0.0316228 f=0.0001 sqrt(f)=0.01 (skipping some output..) f=1e-34 sqrt(f)=1e-17 f=1e-35 sqrt(f)=3.16228e-18 f=1e-36 sqrt(f)=1e-18 f=1e-37 sqrt(f)=3.16228e-19 f=1e-38 sqrt(f)=-inf # WTF ??? f=1e-39 sqrt(f)=-inf ...
So when f is so small that it is represented as a denormal number, the sqrtf function returns PURE GARBAGE instead of returning 0. Or any denormal number. I would accept anything, but not, for fucks sake, a negative number. Not -inf. Please.
I have reported this to Apple (more than one year ago) , I got a reply (one year later), and for them it is not an issue, because the argument of sqrtf being smaller than FLT_MIN allows undefined behaviour (!??). Well, let's agree to disagree. I don't think fast-math should allow the compiler to do whatever it wants. Denormal numbers do happen. Sqrtf is a common function. There is a difference between being fast and slightly incorrect, and being fast and absolutely wrong.
Note: I have not been able to reproduce it with gcc or msvc, or even clang on linux. It is only the mac version of clang/libc++ which is retarded.