Why value of double seems to be changed after assignment?

architecture, c++, compiler-construction

Solution

Hypothesis: you may be seeing the effects of the 80-bit intel FPU.

With the definition `double d = b * c`, the quantity `b * c` is computed with 80-bit precision and rounded to 64-bits when it is stored into `d`. `(a < d)` would be comparing the 64-bit `a` to 64-bit `d`.

OTOH, with the expression `(a < b * c)`, You have an 80-bit arithmetic result `b * c` being compared directly against `a` before leaving the FPU. So the `b*c` result never has its precision clipped by being saved in a 64-bit variable.

You'd have to look at the generated instructions to be sure, and I expect this will vary with compiler versions and optimizer flags.

Problem

The result of the following program is a little bit strange to me on my machine. ``` #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; } ``` Output: ``` $ ./test a < b * c ``` I know double is not that accurate because of the precision. But I don't expect that value changed and give an inconsistent comparison result. If the `a < b * c` get printed out, I do expect that `a < d` should also get printed. But when I run this code on my i686 server and even on my cygwin. I can see `a < b * c` but cannot see `a < d`. This issue has been confirmed to be platform dependent. Is this caused by the different instruction and implementation of double assignment? UPDATE The generated assembly: ``` 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 ```

Original source

Related problems