Reputation: 2613
How do I explain the below:
double o = 2.3;
int i = (int) (o * 100000.0);
double d = i / 100000.0;
System.out.println(d);
prints 2.29999
double o = 2.3;
double i = o * 100000.0;
double d = i / 100000.0;
System.out.println(d);
prints 2.3
When dividing an int by double doesn't java first cast the int as a double then do the division - if so the two code blocks should effectively print the same value?
There seems to be some IEEE 754 floating point precision specifications I'm missing and/or jvm optimizations that inlines
double i = 2.3 * 100000.0;
double d = i / 100000.0;
as double d = 2.3 * 100000.0 / 100000.0; effectively cancelling out the division and making this a no-op.
Thoughts?
Upvotes: 0
Views: 7074
Reputation: 129497
double i = o * 100000.0;
The value of i
after this is 229999.99999999997
(you can see this yourself by adding a simple print statement; it's due to floating-point inaccuracies).
int i = (int) (o * 100000.0);
The value of i
after this is 229999
(i.e. the value above with the fractional part truncated due to the int
cast).
Therefore, in the line
double d = i / 100000.0;
you are using two numerically different i
values in your two snippets (i.e. they differ by about 1), hence the different outputs.
You are correct in saying that when dividing an int by a double, the int is first converted to a double (this is done through the bytecode instruction i2d
).
Upvotes: 1
Reputation: 222362
2.3 is not exactly representable in IEEE-754 64-bit binary floating-point. What happens in your first code sequence is:
2.3
is converted to the nearest representable value, 2.29999999999999982236431605997495353221893310546875.int
, the conversion truncates, producing 229999.Upvotes: 10
Reputation: 533492
There seems to be some IEEE 754 floating point precision specifications I'm missing
When you use (int)
it truncates the fractional part no matter how close it is to the next whole value. It is not reversible as information is lost, so it should be no surprise that you don't get the same result.
What you could do instead is the following
double o = 2.3;
long l = Math.round(o * 100000.0);
double d = l / 100000.0;
System.out.println(d);
jvm optimizations that inlines ... making this a no-op
The JVM might optimise it, but it won't change the result. If an optimisation changes the outcome it is a bug in the optimiser.
Upvotes: 4