Why is
1 + machine_epsilon + machine_epsilon/2
not equal to
1 + machine_epsilon/2 + machine_epsilon?
Roundings occur with different values in the expression leading to different sums.
Let us look at this in smaller steps and using "%a"
.
double eps2 = DBL_EPSILON;
printf("%-17s:%21a + %11a = %21a\n", "1 + eps/2", //
1.0, eps2 / 2.0, 1. + eps2 / 2.0);
printf("%-17s:%21a + %11a = %21a\n", "(1 + eps/2) + eps", //
1.0 + eps2 / 2, eps2, 1.0 + eps2 / 2.0 + eps2);
printf("%-17s:%21a + %11a = %21a\n", "1 + eps", //
1.0, eps2, 1. + eps2);
printf("%-17s:%21a + %11a = %21a\n", "(1 + eps) + eps/2", //
1. + eps2, eps2, 1.0 + eps2 + eps2 / 2.0);
Output
1 + eps/2 : 0x1p+0 + 0x1p-53 = 0x1p+0
(1 + eps/2) + eps: 0x1p+0 + 0x1p-52 = 0x1.0000000000001p+0
1 + eps : 0x1p+0 + 0x1p-52 = 0x1.0000000000001p+0
(1 + eps) + eps/2: 0x1.0000000000001p+0 + 0x1p-52 = 0x1.0000000000002p+0
Consider 3 consecutive double
values, A = 1.0, B = the next biggest double
or 1.0 + eps and the next double
C = 1.0 + 2*eps.
The exact 1 + eps/2
sum is half way between A and B. With typical rounding (round to nearest, ties to even), the sum rounds to the best double
A (down). A is even as its least significant bit is 0, B is odd.
(1 + eps / 2) + eps
sum is then like 1 + eps
, or B.
1 + eps
sum is B.
(1 + eps) + eps / 2
sum is half half way between B and C. With typical rounding (round to nearest, ties to even), the sum rounds to C (up). C is even as its least significant bit is 0, B is odd.
Other possibilities exist if printf("%d\n", FLT_EVAL_METHOD);
is 2
. In that case, all C floating point math here would use long double
for intermediate results and then the final 1st,2nd variant double
results would be expected to be the same.