Pretty basic code:
#include <iostream>
int main() {
std::cout.precision(100);
double a = 9.79999999999063220457173883914947509765625;
double b = 0.057762265046662104872599030613855575211346149444580078125;
const double bConst = 0.057762265046662104872599030613855575211346149444580078125;
double c = a * b;
std::cout << " a: " << a << std::endl;
std::cout << " b: " << b << std::endl;
std::cout << " bConst: " << bConst << std::endl;
std::cout << " c: " << c << std::endl << std::endl;
std::cout << " c/b: " << c / b << std::endl;
std::cout << " c/bConst: " << c / bConst << std::endl;
}
Which outputs:
a: 9.79999999999063220457173883914947509765625
b: 0.057762265046662104872599030613855575211346149444580078125
bConst: 0.057762265046662104872599030613855575211346149444580078125
c: 0.5660701974567474703547986791818402707576751708984375
c/b: 9.7999999999906304282148994388990104198455810546875
c/bConst: 9.79999999999063220457173883914947509765625
As you can see, b
and bConst
seem to be treated using the same value - i.e. it prints for both the same 0.057762265046662104872599030613855575211346149444580078125
value.
So I guess they are "stored" both the same. The only difference is that b
is not const
.
Then, I do the same c / b
operation twice: one time using b
, another time using bConst
.
As you can see, it leads to two different results. And this makes me wonder.
Can you explain technically why this happens?
The "issue" is due to the -freciprocal-math
switch (implied by -Ofast
):
Allow the reciprocal of a value to be used instead of dividing by the value if this enables optimizations. For example
x / y
can be replaced withx * (1/y)
, which is useful if(1/y)
is subject to common subexpression elimination. Note that this loses precision and increases the number of flops operating on the value.
The compiler can calculate d = 1/bConst
at compile time and change from:
c/bConst
to
c * d
but multiplication and division are different instructions with different performance and precision.
See: http://coliru.stacked-crooked.com/a/ba9770ec39ec5ac2
You are using -Ofast
in your link, which enables all -O3
optimizations and includes both -ffast-math
, which in turns includes -funsafe-math-optimizations
.
From what I could glean, with optimizations enabled, -funsafe-math-optimizations
allows the compiler to reduce the precision of some computations. This seems to be what happens in the c/bConst
case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With