Reputation: 20688
Here is my program.
public class Foo
{
public static void main(String[] args)
{
System.out.println((int) 2147483648l);
System.out.println((int) 2147483648f);
}
}
Here is the output.
-2147483648
2147483647
Why isn't 2147483648l
and 2147483648f
type cast to the same integer? Can you explain what is going on here or what concept in Java I need to understand to predict the output of type casts like these?
Upvotes: 39
Views: 3630
Reputation: 1075039
These are examples of the Narrowing Primitive Conversion operation.
In your first example, long
to int
:
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.
So your (int) 2147483648l
is taking the 64 bits of the long
:
00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000
...and dropping the top 32 bits entirely:
10000000 00000000 00000000 00000000
...and taking the remaining 32 bits as an int
. Since the leftmost of those is now a sign bit (long
and int
are stored as two's complement), and since it happens to be set in your 2147483648l
value, you end up with a negative number. Since no other bits are set, in two's complement, that means you have the lowest negative number int
can represent: -2147483648.
The float
to int
example follows a more complex rule. The relevant parts for your value are:
...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).
...[if] the value [is] too large (a positive value of large magnitude or positive infinity), [then] the result of the first step is the largest representable value of type int or long.
(But see the part of the spec linked above for the details.)
So since 2147483648f
rounds to 2147483648
, and 2147483648
is too large to fit in int
, the largest value for int
(2147483647
) is used instead.
So in the long
to int
, it's bit fiddling; in the float
to int
, it's more mathematical.
In a comment you've asked:
Do you know why both
(short) 32768
and(short) 32768f
evaluate to-32768
? I was exepecting the latter to evaluate to32767
.
Excellent question, and that's where my "see the part of the spec linked above for the details" above comes in. :-) (short) 32768f
does, in effect, (short)(int)32768f
:
In the spec section linked above, under "A narrowing conversion of a floating-point number to an integral type T takes two steps:", it says
- In the first step, the floating-point number is converted either to a
long
, if T islong
, or to anint
, if T isbyte
,short
,char
, orint
...
and then later in Step 2's second bullet:
- * If T is
byte
,char
, orshort
, the result of the conversion is the result of a narrowing conversion to type T (§5.1.3) of the result of the first step.
So in step one, 32768f
becomes 32768
(an int
value), and then of course (short)32768
does the bit-chopping we saw in long
=> int
above, giving us a short
value of -32768
.
Upvotes: 75
Reputation: 234785
Nice! It's wonderful to see the effects of design decisions presented in the way that you have.
2147483648l
is a long
type and the rule for converting a long
that's too big for the int
is to apply the wrap-around rule into the destination type. (Under the hood, the significant bits from the source type are simply discarded.)
2147483648f
is a float
type and the rule for converting a float
that's too big for the destination type is to take the largest possible for the destination type. Reference Are Java integer-type primitive casts "capped" at the MAX_INT of the casting type?
The good thing about standards is that there are so many to choose from.
Upvotes: 20