为什么同样的代码在不同的机器上会产生两个不同的 fp 结果?
Why this same code produce two different fp results on different Machines?
代码如下:
#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
),或者 here (GCC
):
errorLn2per12 = 9.3702823278363212011754512786865234375e-12
相反,here (GCC
):
errorLn2per12 = 9.368505970996920950710773468017578125e-12
这是不同的。是因为Machine Epsilon?还是编译器精度标志?或者不同的 IEEE
评价?
造成这种漂移的原因是什么?问题似乎出现在 fabs()
函数中(因为其他值似乎相同)。
即使没有 -Ofast
,C++ 标准也不要求实现与 log
(或 sin
,或 exp
等)完全一致,只是它们在几个 ulp 之内(即最后的二进制位置可能有一些不准确)。这允许更快的硬件(或软件)近似,每个 platform/compiler 可能会有所不同。
(在所有平台上您总能从中获得完美结果的唯一浮点数学函数是 sqrt
。)
更烦人的是,你甚至可能在编译(编译器可能使用一些内部库来精确到 float
/double
允许常量表达式)和运行时(例如硬件)之间得到不同的结果-支持的近似值)。
如果您希望 log
跨平台和编译器给出完全相同的结果,您将不得不自己实现它,仅使用 +
、-
、*
, /
和 sqrt
(或者找一个有这个保证的图书馆)。并在此过程中避免一大堆陷阱。
如果您一般需要浮点确定性,我强烈建议您阅读这篇文章以了解您面临的问题有多大:https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/
代码如下:
#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
),或者 here (GCC
):
errorLn2per12 = 9.3702823278363212011754512786865234375e-12
相反,here (GCC
):
errorLn2per12 = 9.368505970996920950710773468017578125e-12
这是不同的。是因为Machine Epsilon?还是编译器精度标志?或者不同的 IEEE
评价?
造成这种漂移的原因是什么?问题似乎出现在 fabs()
函数中(因为其他值似乎相同)。
即使没有 -Ofast
,C++ 标准也不要求实现与 log
(或 sin
,或 exp
等)完全一致,只是它们在几个 ulp 之内(即最后的二进制位置可能有一些不准确)。这允许更快的硬件(或软件)近似,每个 platform/compiler 可能会有所不同。
(在所有平台上您总能从中获得完美结果的唯一浮点数学函数是 sqrt
。)
更烦人的是,你甚至可能在编译(编译器可能使用一些内部库来精确到 float
/double
允许常量表达式)和运行时(例如硬件)之间得到不同的结果-支持的近似值)。
如果您希望 log
跨平台和编译器给出完全相同的结果,您将不得不自己实现它,仅使用 +
、-
、*
, /
和 sqrt
(或者找一个有这个保证的图书馆)。并在此过程中避免一大堆陷阱。
如果您一般需要浮点确定性,我强烈建议您阅读这篇文章以了解您面临的问题有多大:https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/