it might be too late in the night, but I can't understand the behavior of this code:
public class DT {
static void theTest(double d){
double e = Math.floor(d/1630)*1630;
System.out.println(e-d);
}
public static void main(String[] args) {
theTest(2*1630);
theTest(2*1631);
theTest(2*1629);
theTest(8.989779443802325E18);
}
}
in my understangind, all 4 cases should be NON-positive, i.e. "e" is always <= "d", but I do get following output:
0.0
-2.0
-1628.0
1024.0
Why??. as this is same with FastMath, I suspect something double-specific? but could anyone explain me this?
When you get up into huge numbers, the doubles are spaced more widely than integers. When you do a division in this range, the result can be rounded up or down. So in your fourth test case, the result of the division d/1630
is actually rounded up to the nearest available double. Since this is a whole number, the call to floor
does not change it. Multiplying it by 1630
then gives a result that is larger than d
.
Edit
This effect kicks in at 2^52. Once you get past 2^52, there are no more non-integer doubles. Between 2^52 and 2^53, the doubles are just the integers. Above 2^53, the doubles are spaced more widely than the integers.
The result of the division in the question is 5515202112762162.576...
which is between 2^52 and 2^53. It is rounded to the nearest double, which is the same as the nearest integer, which is 5515202112762163. Now, the floor
does not change this number, and the multiplication by 1630
gives a result that is larger than d
.
In summary, I guess the first sentence of the answer was a little misleading - you don't need the doubles to be spaced more widely than the integers for this effect to occur; you only need them to be spaced at least as widely as the integers.
With a value of d
between 0 and 2^52 * 1630, the program in the question will never output a positive number.