138*_*138 1 c++ g++ clang ieee-754
我遇到了一个似乎与平台相关的错误.我得到了clang ++和g ++的不同结果,但仅限于我的32-Debian Machine.我一直认为IEEE 754是标准化的,所有遵守标准的编译器都会有相同的行为.如果我错了,请告诉我,我对此非常困惑.另外,我意识到依赖浮点比较通常不是一个好主意.
#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;
}
Run Code Online (Sandbox Code Playgroud)
这是我的输出
[~/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
Run Code Online (Sandbox Code Playgroud)
标准允许中间结果使用扩展精度,即使在完全合规模式下(许多编译器默认情况下也没有).它说[basic.fundamental]:
本国际标准对浮点运算的准确性没有要求
有关比较g ++和clang的特殊情况,请参阅https://gcc.gnu.org/wiki/FloatingPointMath
没有任何明确的选择,GCC假定舍入到最近或甚至并且不关心信号NaN.
也
对于没有SSE2支持的传统x86处理器,对于m68080处理器,GCC只能完全符合IEEE双扩展(long double)类型的IEEE 754语义.使用双扩展精度执行IEEE双精度和IEEE单精度值的操作.为了正确舍入这些操作,GCC必须保存FPU控制和状态字,启用舍入到24或53个尾数位,然后恢复FPU状态.这太昂贵了.
由于SSE(64位)和x87(80位)之间的扩展精度不同,编译时计算的结果可能不仅取决于编译器及其版本,还取决于构建编译器的标志.
您知道IEEE 754规则未生效的方式是通过检查numeric_limits<T>::is_iec559.