Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java type casting - float (and long) to int

Tags:

java

casting

I am trying to understand the type casting in Java. I have read that long is converted to int by using reduced modulo by range of int and float is converted to int by removing the fractional part. I tried the following code.

class test
{
    public static void main(String arf[])
    {
        System.out.println((int)2147483648.0);
        System.out.println((int)2147483648L);
    }
}

...where 2147483647 is the maximum value of int.

The output is:

2147483647
-2147483648

When float is converted to int its fractional part is removed. So, (int)2147483648.0 should also equal to -2147483648.

Can anyone explain to me why 2147483648.0 is cast to 2147483647?

like image 554
Rohit Negi Avatar asked Aug 22 '15 14:08

Rohit Negi


3 Answers

2147483648.0 is actually 231, whereas the maximum value for an int is 231-1. So, that floating point value is literally one value too high to fit.

The reason that it's going to truncate it to the highest int value is described in the language specification as a narrowing conversion.

  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, rounding toward zero using IEEE 754 round-toward-zero mode (§4.2.3). Then there are two cases:

    • If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V.

    • Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.

The relevant part here is that the value will round towards zero. So long as the floating-point value (or long) is above Integer.MAX_VALUE, a cast to int will result in its highest value. The same is true for a value that's lower than Integer.MIN_VALUE as well.

Something curious happens if you use (int)-214783649L; it will suddenly become 214783647! Why this happens is also explained in the JLS, emphasis mine:

A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

The long representation of that value in binary with a pipe denoting the 32-bit cut-off, looks like this:

1111 1111 1111 1111 1111 1111 1111 1111 | 0111 1111 1111 1111 1111 1111 1111 1111

When a conversion happens, the first 32 bits are discarded, leaving you with the highest possible int.

The inverse is true with a positive long - the higher 32 bits contain all 1s which are discarded on a conversion.

The full structure is below, with pipe again denoting the 32 bit mark:

1111 1111 1111 1111 1111 1111 1111 1111 | 1000 0000 0000 0000 0000 0000 0000 0000
like image 55
Makoto Avatar answered Nov 15 '22 16:11

Makoto


No matter which greater value (than int max value) you give as a float value, it cuts(fits) down to int max value which is 2147483647

 System.out.println((int)2147483699.0); //2147483647
 System.out.println((int)3147483699.0); //2147483647

Edit :

Range of long in java is -9,223,372,036,854,775,808 and 9,223,372,036,854,775,807 (inclusive). where as -2,147,483,648 and 2,147,483,647 (inclusive).

So if your value of long is larger/lesser than the values given for an int, conversion is never accurate.

like image 40
Suresh Atta Avatar answered Nov 15 '22 18:11

Suresh Atta


The compiler is the smartass here. If you observe the byte code carefully, you can see that the compiler is replacing the float value to Integer.MAX_VALUE.

So, like Suresh says, any float value above 2147483647.0 is replaced by 2147483647.

code :

public static void main(String arf[]) {
        int i = (int) 2147483649121.0f;
        System.out.println(i);
        System.out.println((int) 2147483648L);
    }

Byte code :

public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: ldc           #16                 // HERE : int 2147483647
         2: istore_1      
         3: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
         6: iload_1       
         7: invokevirtual #23                 // Method java/io/PrintStream.println:(I)V
        10: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
        13: ldc           #29                 // int -2147483648
        15: invokevirtual #23                 // Method java/io/PrintStream.println:(I)V
        18: return        
like image 31
TheLostMind Avatar answered Nov 15 '22 17:11

TheLostMind