I am working on some numerical code and I was looking at the compiler output. One particular case struck me as odd:
In real numbers, it holds that abs(a) * abs(b) = abs(a * b). I would expect the same to hold in floating point numbers. However, the optimization is performed neither by clang nor by g++ and I wonder whether I am missing some subtle difference there. Both compilers do however realize that abs(abs(a) * abs(b)) = abs(a) * abs(b).
Here is the relevant piece of code:
#include<cmath>
double fabsprod1(double a, double b) {
return std::fabs(a*b);
}
double fabsprod2(double a, double b) {
return std::fabs(a) * std::fabs(b);
}
double fabsprod3(double a, double b) {
return std::fabs(std::fabs(a) * std::fabs(b));
}
And here is the confusing compiler output in godbolt with gcc-10.1 (current stable version as of writing this) and -O3: https://godbolt.org/z/ZEFPgF
Notably, even with -Ofast, which as far as I understand is more lenient with the transformations that are allowed, this optimization is not performed.
As was pointed out by @Scheff in the comments, double and float are not real numbers. But I also fail to see where corner cases with float types, such as getting Infinity or NaN as argument, could produce different outputs.