Home > other >  Why casting a very large long number to int gives us a strange output (Java)?
Why casting a very large long number to int gives us a strange output (Java)?

Time:05-07

I was practicing some castings in Java and I faced a situation for which I couldn't find any answers, anywhere. There are a lot of similar questions with answers, but none gave me an explanation for this particular case.

When I do something like

    long l = 165787121844687L;
    int i = (int) l;

    System.out.println("long: "   l);
    System.out.println("after casting to int: "   i);

The output is

long: 165787121844687
after casting to int: 1384219087

This result is very intriguing for me.

I know that the type long is a 64-bit integer, and the type int is a 32-bit integer. I also know that when we cast a larger type to a smaller one, we can lose information. And I know that there is a Math.toIntExact() method that is quite useful.

But what's the explanation for this "1384219087" output? There was loss of data, but why this number? How "165787121844687" became "1384219087"? Why does the code even compile?

That's it. Thanks!

CodePudding user response:

165787121844687L in hex notation = 0000 96C8 5281 81CF

1384219087 in hex notation = 5281 81CF

So the cast truncated the top 32 bits as expected.

                        32-bits 
                        deleted 
                       ▼▼▼▼ ▼▼▼▼
165_787_121_844_687L = 0000 96C8 5281 81CF  ➣  1_384_219_087
    64-bit long                  ▲▲▲▲ ▲▲▲▲      32-bit int 
                                  32-bits 
                                 remaining

CodePudding user response:

If you convert these two numbers to hexadecimal, you get

96C8528181CF
528181CF

See what's happened here?

CodePudding user response:

The Answer by OldProgrammer is correct, and should be accepted. Here is some additional info, and a workaround.

Java spec says so

Why does the code even compile?

When you cast a numeric primitive in Java, you take responsibility for the result including the risk of information loss.

Why? Because the Java spec says so. Always best to read the documentation. Programming by intuition is risky business.

See the Java Language Specification, section 5.1.3. Narrowing Primitive Conversion. To quote (emphasis mine):

A narrowing primitive conversion may lose information

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.

Math#…Exact…

When you want to be alerted to data loss during conversion from a long to a short, use the Math methods for exactitude. If the operation overflows, an execution is thrown. You can trap for that exception.

try 
{
   int I = Math.toIntExact( 165_787_121_844_687L ) ;  // Convert from a `long` to an `int`. 
} 
catch ( ArithmeticException e ) 
{ 
    // … handle conversion operation overflowing an `int` …
}

You will find similar Math#…Exact… methods for absolute value, addition, decrementing, incrementing, multiplying, negating, and subtraction.

  • Related