96

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!

AstroCB
  • 12,337
  • 20
  • 57
  • 73
DeaIss
  • 2,525
  • 7
  • 27
  • 37

10 Answers10

334

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

Geek
  • 26,489
  • 43
  • 149
  • 227
Ali Gajani
  • 14,762
  • 12
  • 59
  • 100
  • "The largest decimal literal of type int is 2147483648 (231)." I think you're missing some `` tags. – Joshua Taylor Jun 12 '14 at 01:03
  • 17
    I've added the animation for "Pacman" for symbolic purposes but it also serves as a great visual of how one would see 'integer overflows'. – Ali Gajani Jun 12 '14 at 11:44
  • 9
    This is my favorite answer on this site ever of all times. – Lee White Jun 12 '14 at 14:24
  • 2
    You seem to have missed that this was a doubling sequence, not adding one. – Paŭlo Ebermann Jun 12 '14 at 19:25
  • Ah I realized that, but I think I got the idea across hopefully – Ali Gajani Jun 13 '14 at 06:32
  • 1
    That's pretty cool. I'll probably be linking to this answer in the future. – harold Jun 13 '14 at 07:54
  • Thanks @harold. Hope you found it useful. Will add more to keep it a long term resource for anyone who stumbles upon it. Glad it got semi-viral on SO network :) – Ali Gajani Jun 13 '14 at 08:03
  • 2
    I think the pacman animation got this answer more upvotes than the accepted answer. Have another upvote on me - its one of my favourite games! – Husman Jun 13 '14 at 10:35
  • 3
    For anyone who didn't get the symbolism: https://en.wikipedia.org/wiki/Kill_screen#Pac-Man – wei2912 Jun 14 '14 at 13:19
  • Much surprised that this answer received so much attention because of an animation :) well yes at once I saw it as symbolism but there's a real situation of the kill screen as one commentator suggested. – Ali Gajani Jun 15 '14 at 14:24
  • 1
    I admit that I upvote this question just because the PacMan animation with 200+ upvotes, without reading the rest part of the answer. :) – DnR Jun 16 '14 at 06:51
  • I don't think it is explained here, but knowing what to do with a zero exponent (10^0 or 2^0) is helpful for understanding the decimal vs binary math comparison shown in the illustration. So, what do you do with a zero exponent? http://www.virtualnerd.com/pre-algebra/factors-fractions-exponents/exponent-properties/negative-zero-exponents/zero-exponent-definition – gfullam Jun 19 '14 at 21:28
168

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.

Community
  • 1
  • 1
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 28
    Could you expand on your answer a bit? – DeaIss Jun 11 '14 at 22:16
  • 17
    @oOTesterOo It starts of printing 2, 4 etc but it very quickly reaches the maximum value of the integer and it "wraps around" to negative numbers, once it reaches zero it stays at zero forever – Richard Tingle Jun 11 '14 at 22:17
  • There happens to be two overflows as you correctly noted. The second one is so big, that it directly hits 0. – Artjom B. Jun 11 '14 at 22:20
  • 1
    Could you possibly explain why this situation doesn't happen after 63 iterations when I use a long? – DeaIss Jun 11 '14 at 22:33
  • @oOTesterOo: Because it happens after 64 iterations, and happens after 32 iterations for an `int`. – Louis Wasserman Jun 11 '14 at 22:34
  • 1
    I just did it and i kept increasing WAY after 64 iterations? I left it on an infinite while loop for at least a few minutes and the numbers being printed kept increasing as opposed to hitting a max value or overflowing/underflowing to 0! – DeaIss Jun 11 '14 at 22:37
  • Please post that code, then, because that's not at all what happens when I change the one `int` to `long`. `long` cannot even represent numbers >= 2^63. – Louis Wasserman Jun 11 '14 at 22:42
  • 52
    This answer isn't even complete (it doesn't even _mention_ that the value will _not_ be `0` on the first few iterations, but speed of output is obscuring that fact from the OP). Why is it accepted? – Lightness Races in Orbit Jun 12 '14 at 10:09
  • 16
    Presumably it was accepted because it was considered helpful by the OP. – Joe Jun 12 '14 at 15:33
  • 4
    @LightnessRacesinOrbit Although it doesn't directly address the issues the OP put in their question, the answer gives enough information that a decent programmer should be able to infer what's going on. – Kevin Jun 13 '14 at 17:34
46

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.

peter.petrov
  • 38,363
  • 16
  • 94
  • 159
15
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;
TrungTran05T3
  • 238
  • 1
  • 5
4

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;
}
Kaify
  • 97
  • 8
  • 3
    This program, in C, actually triggers undefined behavior in every execution, which allows the compiler to replace the whole program with anything (even `system("deltree C:")`, since you're in DOS/Windows). Signed integer overflow is undefined behavior in C/C++, unlike Java. Be very careful when using this kind of construct. – filcab Jun 12 '14 at 17:13
  • @filcab : **"replace the whole program with anything"** what are you talking about. I have run this program on Visual studio 2012 and it runs perfectly fine for both `signed and unsigned` integers without any **undefined behavior** – Kaify Jun 13 '14 at 00:03
  • 3
    @Kaify: Working fine is a perfectly valid undefined behaviour. Imagine however that the code did `i += i` for 32+ iterations, then had `if (i > 0)`. The compiler could optimise that to `if(true)` since if we're always adding positive numbers, `i` will always be greater than 0. It could also leave the condition in, where it won't be executed, because of the overflow represented here. Because the compiler could produce two equally valid programs from that code, it's undefined behaviour. – 3Doubloons Jun 13 '14 at 00:13
  • Really, the "UB could mean deleting your hard drive" analogy hurts more than it helps – 3Doubloons Jun 13 '14 at 00:14
  • @3Doubloons : Ok now I am getting what you are talking about ,compiler level lexical analysis and all those stuff , but I am very much confident that today's compiler are very much adaptive to and have atleast the overflows defined . Secondly "replace the program with anhything" is still out of my understanding. – Kaify Jun 13 '14 at 00:41
  • 1
    @Kaify: it's not lexical analysis, it's the compiler compiling your code and, following the standard, being able to do “weird” optimizations. Like the loop that 3Doubloons talked about. Just because compilers that you try always seem to do something, it doesn't mean the standard guarantees your program will always run the same way. You had undefined behavior, some code might have been eliminated since there's no way to get there (UB guarantees that). These posts from the llvm blog (and links in there) have more information: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html – filcab Jun 13 '14 at 03:09
  • @filcab: nice article , I dont know why you kept it secret ,should have put it in your first comment. Thanks anyways. – Kaify Jun 14 '14 at 10:45
  • 2
    @Kaify: Sorry for not putting it, but it's completely wrong to say “kept it a secret”, especially when it's the second result, on Google, for “undefined behavior”, which was the specific term I used for what was being triggered. – filcab Jun 15 '14 at 03:14
  • @filcab: come on now , really!! Its a way of expression.good day, peace out!! – Kaify Jun 15 '14 at 09:28
4

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.

starchild
  • 496
  • 2
  • 8
3

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);
        }
    }
}
Bruno Volpato
  • 1,382
  • 10
  • 18
  • If I use long instead of int, it seems to be print >0 numbers for a long time. Why does it not run into this problem after 63 iterations? – DeaIss Jun 11 '14 at 22:20
  • 1
    "Doesn't calculate correctly" is an incorrect characterization. The calculation is correct according to what the Java spec says should happen. The real issue is that the result of the (ideal) calculation cannot be represented as an `int`. – Stephen C Jun 11 '14 at 22:22
  • @oOTesterOo - because `long` can represent larger numbers than `int` can. – Stephen C Jun 11 '14 at 22:23
  • Long has a larger range. The BigInteger type accepts any value/length that your JVM can allocate. – Bruno Volpato Jun 11 '14 at 22:23
  • I assumed int overflows after 31 iterations because its a 32-bit max sized number, and so long which is a 64-bit would hit its max after 63? Why is that not the case? – DeaIss Jun 11 '14 at 22:24
  • You are right. Take a look at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html – Bruno Volpato Jun 11 '14 at 22:27
  • Sorry still don't understand why when I used a long I didn't see an "overflow" or a "max" value hit after 63 iterations. When I did it it seemed to keep getting larger way after 63 iterations! – DeaIss Jun 11 '14 at 22:31
  • Integer maximum value is 2^31-1, and long 2^63-1, so it will cause problems in the 63rd iteration. My example using BigInteger will work as expected. – Bruno Volpato Jun 11 '14 at 22:36
2

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

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
...
rich remer
  • 3,407
  • 2
  • 34
  • 47
1

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.

René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293
Scooba doo
  • 11
  • 2