MinGW GCC 4.9.1 and floating-point determinism

前端 未结 2 1761
不思量自难忘°
不思量自难忘° 2021-02-13 20:39

I wrote a small program to compute the Euclidean norm of a 3-coordinate vector. Here it is:

#include 
#include 
#include 

        
相关标签:
2条回答
  • 2021-02-13 21:02

    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.

    0 讨论(0)
  • 2021-02-13 21:17

    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 ...

    0 讨论(0)
提交回复
热议问题