浮点算法在g ++和clang ++之间有所不同? [英] Floating point arithmetic varies between g++ and clang++?

查看:90
本文介绍了浮点算法在g ++和clang ++之间有所不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个似乎与平台有关的错误。我在clang ++和g ++上得到了不同的结果,但是仅在我的32 Debian机器上。我总是给人以IEEE 754是标准化的印象,并且所有遵守该标准的编译器都将具有相同的行为。如果我错了,请告诉我,对此我感到非常困惑。另外,我意识到依靠浮点数比较通常不是一个好主意。

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;
}

这是我的输出

[~/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


推荐答案

该标准允许中间结果即使在完全合规模式下(默认情况下很多编译器都没有使用),也要使用扩展精度。它在 [basic.fundamental] 中说:

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

对于您比较g ++和clang的特殊情况,请参见 https://gcc.gnu.org/wiki/FloatingPointMath

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

没有任何明确的选择,GCC会假设舍入到最接近或均匀,并且不关心信号NaN。

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


对于不支持SSE2的旧版x86处理器和m68080处理器,GCC仅能够完全符合IEEE 754语义IEEE双扩展(long double)类型。使用双精度扩展精度执行IEEE双精度和IEEE单精度值的运算。为了使这些操作正确舍入,GCC必须保存FPU控制和状态字,启用舍入到24或53个尾数位,然后恢复FPU状态。这太昂贵了。

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.

由于SSE(64位)和x87(80位)之间的扩展精度不同,编译时计算的结果可能不仅取决于编译器及其版本,还取决于编译器的构建标志。

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.

您知道IEEE 754的方式规则无效,方法是检查 numeric_limits< T> :: is_iec559

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

这篇关于浮点算法在g ++和clang ++之间有所不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆