为什么相同的代码在不同的计算机上产生两个不同的fp结果?

时间:2019-02-14 15:50:54

标签: c++ floating-point floating-accuracy

代码如下:

#include <iostream>
#include <math.h>

const double ln2per12 = log(2.0) / 12.0;

int main() {
    std::cout.precision(100);
    double target = 9.800000000000000710542735760100185871124267578125;
    double unnormalizatedValue = 9.79999999999063220457173883914947509765625;
    double ln2per12edValue = unnormalizatedValue * ln2per12;
    double errorLn2per12 = fabs(target - ln2per12edValue / ln2per12);
    std::cout << unnormalizatedValue << std::endl;
    std::cout << ln2per12 << std::endl;
    std::cout << errorLn2per12 << " <<<<< its different" << std::endl;
}

如果我在自己的计算机(MSVC)或hereGCC)上尝试:

errorLn2per12 = 9.3702823278363212011754512786865234375e-12

相反,hereGCC):

errorLn2per12 = 9.368505970996920950710773468017578125e-12

这是不同的。是由于Machine Epsilon吗?还是编译器精度标志?还是其他IEEE评估?

造成这种漂移的原因是什么? fabs()函数似乎出现了问题(因为其他值似乎相同)。

1 个答案:

答案 0 :(得分:4)

即使没有-Ofast,C ++标准也不要求实现与log(或sinexp等)完全相同,只是在几分之内(即最后的二进制位置可能有一些错误)。这样可以加快硬件(或软件)的逼近速度,每个平台/编译器可能会有不同的估算结果。

在所有平台上始终可以得到完美结果的唯一浮点数学函数是sqrt

更令人讨厌的是,您甚至可能在编译之间得到不同的结果(编译器可能使用一些内部库,使其精确到float / double允许使用常量表达式)和运行时(例如,硬件支持近似值。)

如果您希望log在平台和编译器之间提供完全相同的结果,则您只能自己使用+-*,{ {1}}和/(或找到具有此保证的库)。并避免沿途出现很多陷阱。

如果您通常需要浮点确定性,强烈建议阅读本文以了解您面临的问题有多严重:https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/