我想知道为什么分别在x86和x64上使用pow时会观察到不同的结果。在我们的应用程序中,我们控制浮点舍入模式,该模式在Windows和Linux 32位上均运行良好。

#include <cmath>
#include <cstdio>
#include <cfloat>

void checkEqual(double expected, double observed) {
    if (expected == observed) {
        printf("Expected %.23f, got %.23f\n", expected, observed);
    }
    else {
        printf("ERROR: Expected %.23f, got %.23f\n", expected, observed);
    }
}

int main(int argc, char **argv) {
    unsigned ret, tmp;
    _controlfp_s(&ret, 0, 0);
    _controlfp_s(&tmp, RC_DOWN, MCW_RC);

    checkEqual(2048.0, pow(2.0, 11.0));
    checkEqual(0.125, pow(2.0, -3.0));

    return 0;
}

使用Visual Studio 2015进行编译和运行(2012将获得相同的结果),输出如下

x86:
Expected 2048.00000000000000000000000, got 2048.00000000000000000000000
Expected 0.12500000000000000000000, got 0.12500000000000000000000

x64:
ERROR: Expected 2048.00000000000000000000000, got  2047.99999999999977262632456
ERROR: Expected 0.12500000000000000000000, got 0.12499999999999998612221

谁能解释差异?我知道,从本质上讲,浮点计算并不精确,但是对于这些特定值,无论四舍五入模式如何,我都希望该函数产生相同的结果。

我对此进行了更多研究,发现真正的问题不是pow的实现方式,而是x86和x64硬件与Hans Passant所建议的不同。

最佳答案

pow可能有许多不同的实现。例如,pow(x,y)exp(y*ln(x))。可以想象,即使exp(11.0*ln(2.0))x可以精确表示,但y可能会遭受内部舍入错误。

但是,使用整数参数调用pow是很常见的,因此某些库针对这些情况优化了路径。例如,pow(x,2*n)pow(x,n)的平方,pow(x, 2n+1)x*pow(x, 2n)

看来您的x86和x64实现在这方面有所不同。那可能发生。 IEEE仅保证+-* /和sqrt的精确结果。

关于c++ - x86和x64上pow的不同结果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36477244/

10-09 06:37
查看更多