Floating point arithmetic varies between g++ and clang++?

て烟熏妆下的殇ゞ 提交于 2019-12-11 13:40:37

问题


I have come across a bug that seems to be platform dependent. I am getting different results for clang++ and g++ however only on my 32-Debian Machine. I was always under the impression that IEEE 754 was standardized and that all compilers that abide by the standard would have the same behavior. Please let me know if I am wrong, I am just very confused about this. Also, I realize that depending on floating point comparison is generally not a good idea.

#define DEBUG(line) std::cout <<"\t\t" << #line << " => " << line << "\n";
#include <iostream>
int main() {
    double x = 128.0, y = 255.0;
    std::cout << "\n";
    DEBUG(  x/y)
    DEBUG(  ((x/y) == 128.0/255.0)) 
    DEBUG(  (128.0/255.0)   )
    DEBUG(  ((x/y)-(x/y)))
    DEBUG(  ((x/y)-(128.0/255.0))   )  
    DEBUG(  ((128.0/255.0)-0.501961) ) 
    std::cout << "\n";  
    return 0;
}

And here is my output

[~/Desktop/tests]$ g++ float_compare.cc -o fc
[~/Desktop/tests]$./fc

        x/y => 0.501961
        ((x/y) == 128.0/255.0) => 0
        (128.0/255.0) => 0.501961
        ((x/y)-(x/y)) => 0
        ((x/y)-(128.0/255.0)) => 6.9931e-18
        ((128.0/255.0)-0.501961) => -2.15686e-07

[~/Desktop/tests]$clang++ float_compare.cc -o fc
[~/Desktop/tests]$./fc

        x/y => 0.501961
        ((x/y) == 128.0/255.0) => 1
        (128.0/255.0) => 0.501961
        ((x/y)-(x/y)) => 0
        ((x/y)-(128.0/255.0)) => 0
        ((128.0/255.0)-0.501961) => -2.15686e-07

回答1:


The Standard allows intermediate results to use extended precision, even in full compliance mode (which many compilers aren't in by default). It says in [basic.fundamental]:

This International Standard imposes no requirements on the accuracy of floating-point operations

For your particular situation comparing g++ and clang, see https://gcc.gnu.org/wiki/FloatingPointMath

Without any explicit options, GCC assumes round to nearest or even and does not care about signalling NaNs.

also

For legacy x86 processors without SSE2 support, and for m68080 processors, GCC is only able to fully comply with IEEE 754 semantics for the IEEE double extended (long double) type. Operations on IEEE double precision and IEEE single precision values are performed using double extended precision. In order to have these operations rounded correctly, GCC would have to save the FPU control and status words, enable rounding to 24 or 53 mantissa bits and then restore the FPU state. This would be far too expensive.

Since extended precision is different between SSE (64-bit) and x87 (80-bit), the results of compile-time computations may depend not only on the compiler and its version, but also what flags the compiler was built with.

The way you know that IEEE 754 rules are not in effect is by checking numeric_limits<T>::is_iec559.



来源:https://stackoverflow.com/questions/49471943/floating-point-arithmetic-varies-between-g-and-clang

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!