I wrote a small program to compute the Euclidean norm of a 3-coordinate vector. Here it is:
#include
#include
#include
There is a difference in precision of a floating point number depending on where it is stored. If the compiler keeps one variable in a register, it has higher precision as a variable stored in memory. You can try to force your variables to be stored in memory before, like:
int main()
{
std::array<double, 3u> arr = { 4.0, -2.0, 6.0 };
volatile double v1 = norm(arr);
volatile double v2 = norm(arr);
std::cout << v1 - v2 << '\n';
}
This gives you the expected result of 0.
As @MatthiasB pointed out, this seems to be an issue of gcc temporarily storing an 80 bit floating point value into a 64 bit register/memory location. Consider the following simplified program which still reproduces the issue:
#include <cmath>
#include <iostream>
double norm() {
double res = 4.0 * 4.0 + (-2.0 * -2.0) + (6.0 * 6.0);
return std::sqrt(res);
}
int main() {
std::cout << norm() - norm() << '\n';
return 0;
}
The assembly code of the essential part norm() - norm()
looks like this (using 32 bit mingw 4.8.0 compiler)
...
call __Z4normv ; call norm()
fstpl -16(%ebp) ; store result (80 bit) in temporary (64 bit!)
call __Z4normv ; call norm() again
fsubrl -16(%ebp) ; subtract result (80 bit) from temporary (64 bit!)
...
Essentially, I would consider this a gcc bug, but it seems to be a complicated topic ...