Why does setting a const variable (which will be stored with the same value) lead to a different result once divided?

  • A+

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 with x * (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 * d 

but multiplication and division are different instructions with different performance and precision.

See: http://coliru.stacked-crooked.com/a/ba9770ec39ec5ac2


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: