Search code examples
javacastingintegerdouble

What are the rounding rules of Java Explicit Cast from Double to Int


Ran into a weird quirk when demonistrating Java explicit type casting today and was wondering why this happens.

If I convert a double into an int, and my number is .9 up to 16 precision, it will round up. (See comments in code) If I make it 15 precision it rounds down.

Similarly, if I make my number .8... it will still round down.

        double a = 5.9999999999999999;// 16 precision rounds to 6
        double a1 = 5.8888888888888888; // 16 precision rounds to 5
        double b = 5.999999999999999;// 15 precision rounds to 5
        double c = 5.111111111111111111111111111111111111111; //rounds to 5
        int cast = (int)a;
        for (int i = 0 ; i < 1000000 ; i++){
            System.out.print(cast);
        }

Initially thought I was overflowing the int, but it doesn't appear that is the case.

Any thoughts?


Solution

  • Casting conversions that involve a narrowing primitive conversion from a floating point type to an integral type will round to zero, according to the JLS Section 5.1.3:

    A narrowing conversion of a floating-point number to an integral type T takes two steps:

    1. In the first step, the floating-point number is converted either to a long, if T is long, or to an int, if T is byte, short, char, or int, as follows:
    • If the floating-point number is NaN (§4.2.3), the result of the first step of the conversion is an int or long 0.
    • Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V using the round toward zero rounding policy (§4.2.4).

    So why does double a = 5.9999999999999999; seemingly round up? The double literal has to be converted to a double value first. This is covered by the Floating-Point Literals section of the JLS (3.10.2):

    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.

    Ok, let's go to valueOf for Double:

    [The string value] 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.

    (bold emphasis mine)

    At 16 digits of precision beyond the decimal point (you have 17 include 5), you are pushing the limits of precision for a double literal. At this point, 5.9999999999999999 is closer to 6 than the next lower double value.

    So, 6 is displayed because your floating point literal gets rounded up to 6.0 as a double before it gets cast to an int, and 6.0 cast to an int is the 6 you see printed.

    Other values you have don't get rounded all the way up to 6.0 as double literals, so the cast to int brings it all the way down to 5.