user5108_Dan
user5108_Dan

Reputation: 379

Why do these 2 simple pieces of code give different results?

I suppose this is a rather rudimentary question, but I don't know why these 2 pieces of code give different results. Does the Pentium handle the variable Divider differently than the intermediate value ( 256.0 / (double)k )?

int j=64, k=20;  
double x, y, Divider;

Divider = 256.0 / (double)k;
x = (double)j / Divider - 5.0;
y = (double)j / ( 256.0 / (double)k ) - 5.0;

Results: x = -2.77555756156289E-16 y = 0.0

For reference, I am using Embarcadero's XE3 C++ Builder, which gives the same results as Builder 6. I am using the default compiler settings on both.

Upvotes: 2

Views: 167

Answers (2)

rici
rici

Reputation: 241881

The issue is that when you don't use SSE instructions, the compiler may well chose to do intermediate computations with the native 387 floating point unit, which does all computations with 80-bit values.

In the computation of x, you force the intermediate value to be truncated to 64 bits by storing it in Divisor. Then the next division uses an already rounded divisor; since the division is done with enough precision, the result is slightly different from 5.0.

In the computation of y, the division is done with 80-bit precision, so that the result is closer to 5.0 (sufficiently close that truncating to 64 bits makes it 0).

You would also get two 0 values if you use SSE (which only has 64-bit registers), or otherwise forced the compiler to do all computations with 64-bit precision.

Upvotes: 2

dseiple
dseiple

Reputation: 638

Perhaps it is the optimizer. In the second one

y = (double)j / ( 256.0 / (double)k )

is the same mathematically as

y = (double)j * (double)k / 256.0

This only does one division (which coincidentally divides cleanly) and is subject to less rounding error.

For x it is forced to do two divisions.

Upvotes: 0

Related Questions