为什么在赋值后似乎改变了双倍的价值?

Sta*_*kER 11 c++ architecture compiler-construction

在我的机器上,以下程序的结果对我来说有点奇怪.

#include <iostream>

using namespace std;

int main(){
    double a = 20;
    double b = 0.020;
    double c = 1000.0;

    double d = b * c;

    if(a < b * c)
        cout << "a < b * c" << endl;

    if(a < d)
        cout << "a < d" << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

$ ./test
a < b * c
Run Code Online (Sandbox Code Playgroud)

由于精度的原因,我知道双精度并不准确.但是我不希望这个值发生变化并且给出不一致的比较结果.

如果a < b * c打印出去,我确实也a < d应该打印出来.但是当我在我的i686服务器甚至我的cygwin上运行此代码时.我可以看到,a < b * c但看不到a < d.

此问题已被确认为依赖于平台.这是由双重赋值的不同指令和实现引起的吗?

UPDATE

生成的程序集:

main:
.LFB1482:
    pushl   %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $56, %esp
.LCFI2:
    andl    $-16, %esp
    movl    $0, %eax
    subl    %eax, %esp
    movl    $0, -8(%ebp)
    movl    $1077149696, -4(%ebp)
    movl    $1202590843, -16(%ebp)
    movl    $1066695393, -12(%ebp)
    movl    $0, -24(%ebp)
    movl    $1083129856, -20(%ebp)
    fldl    -16(%ebp)
    fmull   -24(%ebp)
    fstpl   -32(%ebp)
    fldl    -16(%ebp)
    fmull   -24(%ebp)
    fldl    -8(%ebp)
    fxch    %st(1)
    fucompp
    fnstsw  %ax
    sahf
    ja  .L3
    jmp .L2

    //.L3 will call stdout
Run Code Online (Sandbox Code Playgroud)

Bil*_*hue 5

假设:您可能会看到80位英特尔FPU的影响.

根据定义double d = b * c,数量b * c以80位精度计算,并在存储时舍入为64位d.(a < d)将比较64位a到64位d.

OTOH,使用表达式(a < b * c),在离开FPU之前,您b * c将直接比较80位算术结果a.因此,b*c结果永远不会被保存在64位变量中.

您必须查看生成的指令以确定,并且我希望这会随编译器版本和优化程序标志而变化.