3
System.out.println((int)(99.9999999999999));

returns 99

System.out.println((int)(99.999999999999999999999999999999999999999));

returns 100

Can you explain me why?

user3561614
  • 1,024
  • 1
  • 12
  • 20

2 Answers2

5

The double literal 99.9999999999999 can be represented as a double which is less than 100, so the cast to int truncates the decimal part and 99 is the result.

The double literal 99.999999999999999999999999999999999999999 has the closest actual value of 100, and casting to int is simply 100 here.

System.out.println(99.9999999999999);
System.out.println((int)(99.9999999999999));
System.out.println(99.9999999999999 == 100.0);

System.out.println(99.999999999999999999999999999999999999999);
System.out.println((int)(99.999999999999999999999999999999999999999));
System.out.println(99.999999999999999999999999999999999999999 == 100.0);

I used 100.0 as a double literal here, to compare 2 double values to see if they are the exact same double value.

This prints out:

99.9999999999999
99
false
100.0
100
true

The JLS, Section 3.10.2 covers floating point literals:

The details of proper input conversion from a Unicode string representation of a floating-point number to the internal IEEE 754 binary floating-point representation are described for the methods valueOf of class Float and class Double of the package java.lang.

And Double.valueOf javadocs state:

Otherwise, s is regarded as representing an exact decimal value in the usual "computerized scientific notation" or as an exact hexadecimal value; this exact numerical value is then conceptually converted to an "infinitely precise" binary value that is then rounded to type double by the usual round-to-nearest rule of IEEE 754 floating-point arithmetic, which includes preserving the sign of a zero value.

(emphasis mine)

That is, the value is rounded to produce the actual double value.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • Nice answer! Maybe you could also explain why you wrote 100.0 instead of 100 ? – P. Camilleri Apr 22 '14 at 18:20
  • Try: System.out.println(99.999999999999999999999999999999999999999 == 100.0); --> prints true – Raul Guiu Apr 22 '14 at 18:20
  • @M.Massias I have included why I wrote 100.0 instead of 100, along with additional cites and explanations as to why this code behaves this way. – rgettman Apr 22 '14 at 18:25
  • Thank you! So `(int)((Math.random() * ((long)Integer.MAX_VALUE-Integer.MIN_VALUE) + Integer.MIN_VALUE))` is a bad idea to choose a randome int, because it is nearly never Integer.MAX_VALUE? – user3561614 Apr 22 '14 at 18:30
  • To get a random number across the entire range of possible `int` values, just use the [`Random` class's `nextInt()` method](http://docs.oracle.com/javase/8/docs/api/java/util/Random.html#nextInt--). – rgettman Apr 22 '14 at 18:35
  • That's a good method, but I'm interested in understanding why the fragment above works or not. – user3561614 Apr 22 '14 at 18:41
1

Parsing a floating point value occurs at compile time. The javac compiler rounds the value to 100 before it ever emits any code into your .class file, because the most accurate representation of the number you wrote is not 99.9999999999 but 100: You're .0000000000099999999 closer to 100 than you are to 99.999999999 (I was probably inconsistent with my number of digits there). I wrote something that might help you on the .NET Code Generation blog. Nothing I wrote applies any differently to Java than it does to C# (or C++ or any other language that uses floating point)

Kevin Frei
  • 396
  • 2
  • 7