Why does i = i + i give me 0?

JavaMathVariable Assignment

Java Problem Overview


I have a simple program:

public class Mathz {
	static int i = 1;
	public static void main(String[] args) {	
		while (true){
			i = i + i;
			System.out.println(i);
		}
	}
}

When I run this program, all I see is 0 for i in my output. I would have expected the first time round we would have i = 1 + 1, followed by i = 2 + 2, followed by i = 4 + 4 etc.

Is this due to the fact that as soon as we try to re-declare i on the left hand-side, its value gets reset to 0?

If anyone can point me into the finer details of this that would be great.

Change the int to long and it seems to be printing numbers as expected. I'm surprised at how fast it hits the max 32-bit value!

Java Solutions


Solution 1 - Java

Introduction

The problem is integer overflow. If it overflows, it goes back to the minimum value and continues from there. If it underflows, it goes back to the maximum value and continues from there. The image below is of an Odometer. I use this to explain overflows. It's a mechanical overflow but a good example still.

In an Odometer, the max digit = 9, so going beyond the maximum means 9 + 1, which carries over and gives a 0 ; However there is no higher digit to change to a 1, so the counter resets to zero. You get the idea - "integer overflows" come to mind now.

enter image description here enter image description here

> The largest decimal literal of type int is 2147483647 (231-1). All > decimal literals from 0 to 2147483647 may appear anywhere an int > literal may appear, but the literal 2147483648 may appear only as the > operand of the unary negation operator -. > > > If an integer addition overflows, then the result is the low-order > bits of the mathematical sum as represented in some sufficiently large > two's-complement format. If overflow occurs, then the sign of the > result is not the same as the sign of the mathematical sum of the two > operand values.

Thus, 2147483647 + 1 overflows and wraps around to -2147483648. Hence int i=2147483647 + 1 would be overflowed, which isn't equal to 2147483648. Also, you say "it always prints 0". It does not, because http://ideone.com/WHrQIW. Below, these 8 numbers show the point at which it pivots and overflows. It then starts to print 0s. Also, don't be surprised how fast it calculates, the machines of today are rapid.

268435456
536870912
1073741824
-2147483648
0
0
0
0

Why integer overflow "wraps around"

Original PDF

Solution 2 - Java

The issue is due to integer overflow.

In 32-bit twos-complement arithmetic:

i does indeed start out having power-of-two values, but then overflow behaviors start once you get to 230:

> 230 + 230 = -231 > > -231 + -231 = 0

...in int arithmetic, since it's essentially arithmetic mod 2^32.

Solution 3 - Java

No, it does not print only zeros.

Change it to this and you will see what happens.

    int k = 50;
    while (true){
        i = i + i;
        System.out.println(i);
        k--;
        if (k<0) break;
    }

What happens is called overflow.

Solution 4 - Java

static int i = 1;
	public static void main(String[] args) throws InterruptedException {
		while (true){
            i = i + i;
            System.out.println(i);
            Thread.sleep(100);
        }
	}

out put:

2
4
8
16
32
64
...
1073741824
-2147483648
0
0

when sum > Integer.MAX_INT then assign i = 0;

Solution 5 - Java

Since I don't have enough reputation I cannot post the picture of the output for the same program in C with controlled output, u can try yourself and see that it actually prints 32 times and then as explained due to overflow i=1073741824 + 1073741824 changes to -2147483648 and one more further addition is out of range of int and turns to Zero .

#include<stdio.h>
#include<conio.h>

int main()
{
static int i = 1;

    while (true){
        i = i + i;
      printf("\n%d",i);
	  _getch();
	}
	  return 0;
}

Solution 6 - Java

The value of i is stored in memory using a fixed quantity of binary digits. When a number needs more digits than are available, only the lowest digits are stored (the highest digits get lost).

Adding i to itself is the same as multiplying i by two. Just like multiplying a number by ten in decimal notation can be performed by sliding each digit to the left and putting a zero on the right, multiplying a number by two in binary notation can be performed the same way. This adds one digit on the right, so a digit gets lost on the left.

Here the starting value is 1, so if we use 8 digits to store i (for example),

  • after 0 iterations, the value is 00000001
  • after 1 iteration , the value is 00000010
  • after 2 iterations, the value is 00000100

and so on, until the final non-zero step

  • after 7 iterations, the value is 10000000
  • after 8 iterations, the value is 00000000

No matter how many binary digits are allocated to store the number, and no matter what the starting value is, eventually all of the digits will be lost as they are pushed off to the left. After that point, continuing to double the number will not change the number - it will still be represented by all zeroes.

Solution 7 - Java

It is correct, but after 31 iterations, 1073741824 + 1073741824 doesn't calculate correctly (overflows) and after that prints only 0.

You can refactor to use BigInteger, so your infinite loop will work correctly.

public class Mathz {
    static BigInteger i = new BigInteger("1");
    
    public static void main(String[] args) {    
    	
        while (true){
            i = i.add(i);
            System.out.println(i);
        }
    }
}

Solution 8 - Java

For debugging such cases it is good to reduce the number of iterations in the loop. Use this instead of your while(true):

for(int r = 0; r<100; r++)

You can then see that it starts with 2 and is doubling the value until it is causing an overflow.

Solution 9 - Java

I'll use an 8-bit number for illustration because it can be completely detailed in a short space. Hex numbers begin with 0x, while binary numbers begin with 0b.

The max value for an 8-bit unsigned integer is 255 (0xFF or 0b11111111). If you add 1, you would typically expect to get: 256 (0x100 or 0b100000000). But since that's too many bits (9), that's over the max, so the first part just gets dropped, leaving you with 0 effectively (0x(1)00 or 0b(1)00000000, but with the 1 dropped).

So when your program runs, you get:

1 = 0x01 = 0b1
2 = 0x02 = 0b10
4 = 0x04 = 0b100
8 = 0x08 = 0b1000
16 = 0x10 = 0b10000
32 = 0x20 = 0b100000
64 = 0x40 = 0b1000000
128 = 0x80 = 0b10000000
256 = 0x00 = 0b00000000 (wraps to 0)
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
...

Solution 10 - Java

The largest decimal literal of type int is 2147483648 (=231). All decimal literals from 0 to 2147483647 may appear anywhere an int literal may appear, but the literal 2147483648 may appear only as the operand of the unary negation operator -.

If an integer addition overflows, then the result is the low-order bits of the mathematical sum as represented in some sufficiently large two's-complement format. If overflow occurs, then the sign of the result is not the same as the sign of the mathematical sum of the two operand values.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDeaIssView Question on Stackoverflow
Solution 1 - JavaAli GajaniView Answer on Stackoverflow
Solution 2 - JavaLouis WassermanView Answer on Stackoverflow
Solution 3 - Javapeter.petrovView Answer on Stackoverflow
Solution 4 - JavaTrungTran05T3View Answer on Stackoverflow
Solution 5 - JavaKaifyView Answer on Stackoverflow
Solution 6 - JavastarchildView Answer on Stackoverflow
Solution 7 - JavaBruno VolpatoView Answer on Stackoverflow
Solution 8 - Javauser3732069View Answer on Stackoverflow
Solution 9 - Javarich remerView Answer on Stackoverflow
Solution 10 - JavaScooba dooView Answer on Stackoverflow