15

I have been trying this int and long conversion where I have tried assigning an int variable to a long variable. The code is as follows:

public static void main(String []args){
    int i = 1024;
    long j = i;
    long k = i*i*i*i;
    System.out.println("j= " +j+ ", k= " +k);
}

So, while printing j, it simply gave an output of 1024. But while printing k, it showed an overflow (k=0). I sorted out this problem by using this technique, where I have explicitly casted each i to long. i.e.

public static void main(String []args){
    int i = 1024;
    long j = i;
    long k = ((long)i)*((long)i)*((long)i)*((long)i);
    System.out.println("j= " +j+ ", k= " +k);
}

Now, it showed correct values of both j and k. So, I wanted to know why is this needed to cast int in the second case but not in the first one. k, being a long can retain this value after this heavy assignment. But, why it is not been correctly assigned?

dav_i
  • 27,509
  • 17
  • 104
  • 136
Shashish Chandra
  • 489
  • 2
  • 5
  • 20
  • casting first `i` to long should be enough – Display Name Jul 15 '14 at 19:01
  • 4
    The defective pattern you have identified -- a multiplication of integers that could overflow that is converted "too late" to a larger type -- is relatively common in both C# and Java; we find more than five instances per million lines of code analyzed. A related defect with a similar discovery rate is a division of two integers and a "too late" conversion to a double; people are often surprised that three hundred divided by five hundred and assigned to a double is zero, not 0.6. – Eric Lippert Jul 15 '14 at 19:07

5 Answers5

19

The reason is that your line

long k = i*i*i*i;

can be thought of as

long k = ((i*i)*i)*i;

or...

int k1 = i*i;
int k2 = k1*i;
int k3 = k2*i;
long k = k3;

So when any of kn overflows, you get the error.

When you do your casts you're obviously circumventing this problem by always multiplying longs together.

Of course the simplest modification to your initial program is to define i as a long straight away, instead of an int.

long i = 1024L;
dav_i
  • 27,509
  • 17
  • 104
  • 136
7

This problem is based on the fact that different types use different amount of memory. int and long are both Integers, the difference is that int is 4 bytes, while long is 8 bytes.

Lets modify your code a bit:

public class Test {


  public static void main(String []args){
        int i = 1024;
        long j = i;
        long k = i*i*i;

        System.out.println("My multipliers are of type int:");
        System.out.println("j= " +j+ ", k= " +k);           
        System.out.println("Is k less than Integer.MAX_VALUE: "  + (k < Integer.MAX_VALUE? "YES" : "NO"));
        k = i*i*i*i;
        System.out.println("j= " +j+ ", k= " +k);

        //now multiplying with j instead of i
        System.out.println("\nNow Im working with a long type:");
        k = j*j*j;
        System.out.println("j= " +j+ ", k= " +k);           
        System.out.println("Is k less than Integer.MAX_VALUE: "  + (k < Integer.MAX_VALUE? "YES" : "NO"));
        k = j*j*j*j;
        System.out.println("j= " +j+ ", k= " +k);
        System.out.println("Is k less than Integer.MAX_VALUE: "  + (k < Integer.MAX_VALUE? "YES" : "NO"));
        k = j*j*j*j;

     }

}

The code above shows that when you have multiplied i 3 times the result is a value that is smaller than Integer.MAX_VALUE (which is 2147483647), and when youre multiplying it 4 times the result is 0 since there is no enough place in the poor 4 bytes of the multipliers. :) But you can see that when the multipliers (right side, j) are of type long, the correct value is printed, and the last printing shows that the statement k < Integer.MAX_VALUE is false, which is the reason for your zero. :)

Laf
  • 7,965
  • 4
  • 37
  • 52
Ranic
  • 443
  • 3
  • 10
6

i*i*i*i is an all int multiplication so the resultant is integer only (Which is overflowing in your case). for a long resultant you only need to convert one of them to long so this is sufficient

long k = ((long)i)*i*i*i;
Sanjeev
  • 9,876
  • 2
  • 22
  • 33
  • Does associativity come into play here? I meant, if it is right associative, then, if it crosses the integer_max_value previously before coming to the (long i), it will show an overflow again in your case. – Shashish Chandra Jul 15 '14 at 10:32
  • try it @ShashishChandra – Sanjeev Jul 15 '14 at 10:33
  • 1
    I have tried it, and thanks to you, it worked out. I was just asking, is there any role of associativity here? – Shashish Chandra Jul 15 '14 at 10:34
  • Yes, there is .. try converting the last one to long instead of first one. you will see. – Sanjeev Jul 15 '14 at 10:37
  • 1
    So, it is left associative and it will work that way only. Thanks for your reply, I really appreciate it. – Shashish Chandra Jul 15 '14 at 10:39
  • There seems to be a little problem here: pls look here: http://ideone.com/fork/gdvZ5y It also works the other way round since `i*i*i` < Integer_max_value. :) – Shashish Chandra Jul 15 '14 at 10:56
  • 1
    Yes, It will work in that case. because the fourth multiplication with `i` takes it beyond `Integer.MaxValue`. So both approach will work. but if you chose `i` higher so that three multiplication goes beyond `Integer.MaxValue`, you will see the behavior. – Sanjeev Jul 15 '14 at 11:29
2

In first the value of i is an int and the integer multipllication happening and i*i*i*i result is integer and hence the integer overflow.

Where as in second case you are explicitly telling/making the result as long.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
2

1099511627776 which is the result of multiplication is >Integer.MAX_VALUE as it's Integer Multiplication so after i*i*i value would be 1073741824 but after multiplication with 1024 it becomes out of range which causes integer overflow and k will be 0.

  • You can cast one of the i to long
  • Multiply with 1L (1L*i*i*i*i) But NOT i*i*i*i*1L
  • You can also assign i*i*i to long and than multiply with i like this long k =(k=i*i*i)*i;
akash
  • 22,664
  • 11
  • 59
  • 87