为什么 i = i + i 给我0?

我有个简单的计划:

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

当我运行这个程序时,我在输出中看到的只是 i0。我本以为第一轮我们会有 i = 1 + 1,接着是 i = 2 + 2,接着是 i = 4 + 4等等。

这是否是因为一旦我们尝试在左侧重新声明 i,它的值就会被重置为 0

如果有人能告诉我更详细的细节,那就太好了。

int改为 long,它似乎正在按预期打印数字。我很惊讶它达到最大32位值的速度!

22647 次浏览

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.

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.

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);
}
}
}

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

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.

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;

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.

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;
}

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.

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
...