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

时间:2014-06-11 22:12:04

标签: java math variable-assignment

我有一个简单的程序:

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

当我运行此程序时,我在输出中看到0的{​​{1}}。我原本预计第一次会有i,然后是i = 1 + 1,然后是i = 2 + 2等。

这是因为我们尝试在左侧重新声明i = 4 + 4时,其值会重置为i吗?

如果有人能指出我的精细细节,那就太棒了。

0更改为int,似乎是按预期打印数字。我对它达到最大32位值的速度感到惊讶!

10 个答案:

答案 0 :(得分:334)

简介

问题是整数溢出。如果它溢出,它会回到最小值并从那里继续。如果它下溢,它会回到最大值并从那里继续。下图是里程表。我用它来解释溢出。这是一个机械溢出,但仍然是一个很好的例子。

在里程表中,max digit = 9,超出最大值意味着9 + 1,其结束并给出0;但是,没有更高的数字可以更改为1,因此计数器会重置为zero。你明白了 - 现在想到“整数溢出”。

enter image description here enter image description here

  

int类型的最大十进制文字是2147483647(2 31 -1)。所有   从0到2147483647的十进制文字可能出现在int的任何地方   文字可能会出现,但文字2147483648可能只出现   一元否定算子的操作数 - 。

     

如果整数加法溢出,则结果为低位   数学和的位用一些足够大的数字表示   二进制补码格式。如果发生溢出,则表示符号   结果与两者的数学和的符号不同   操作数值。

因此,2147483647 + 1溢出并包裹到-2147483648。因此int i=2147483647 + 1将溢出,这不等于2147483648。另外,你说“它总是打印0”。它没有,因为 http://ideone.com/WHrQIW 。下面,这8个数字表示它转动和溢出的点。然后它开始打印0。此外,不要惊讶它的计算速度有多快,今天的机器很快。

268435456
536870912
1073741824
-2147483648
0
0
0
0

为什么整数溢出“包裹”

                           Original PDF

答案 1 :(得分:168)

问题是整数溢出造成的。

在32位二进制补码算法中:

i确实开始具有两个幂的值,但是一旦你到达2 30 ,溢出行为就开始了:

  

2 30 + 2 30 = -2 31

     

-2 31 + -2 31 = 0

...在int算术中。

答案 2 :(得分:46)

不,它不会只打印零。

将其更改为此,您将看到会发生什么。

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

发生的事情称为溢出。

答案 3 :(得分: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;

答案 4 :(得分:4)

由于我没有足够的声誉,我无法在带有受控输出的C中发布相同程序的输出图片,你可以尝试自己看看它实际打印32次然后由于溢出而解释 i = 1073741824 + 1073741824 更改为 -2147483648 还有一个进一步的加法超出了int的范围并变为 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;
}

答案 5 :(得分:4)

使用固定数量的二进制数字将i的值存储在内存中。当一个数字需要的数字多于可用数字时,只存储最低位数(最高位数会丢失)。

i添加到自身与将i乘以2相同。就像将十进制数字乘以10一样,可以通过将每个数字向左滑动并在右边放置零来执行,以二进制表示法将数字乘以2可以以相同的方式执行。这会在右侧添加一位数字,因此数字会在左侧丢失。

此处起始值为1,因此如果我们使用8位数来存储i(例如),

  • 经过0次迭代后,值为00000001
  • 经过1次迭代后,值为00000010
  • 经过2次迭代后,值为00000100

等等,直到最后的非零步骤

  • 经过7次迭代后,值为10000000
  • 经过8次迭代后,值为00000000

无论分配多少二进制数来存储数字,无论起始值是多少,最终所有数字都会丢失,因为它们被推到左边。在那之后,继续加倍数字将不会改变数字 - 它仍将由全零表示。

答案 6 :(得分:3)

这是正确的,但经过31次迭代后,1073741824 + 1073741824无法正确计算,之后只打印0。

你可以重构使用BigInteger,这样你的无限循环就能正常工作。

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

答案 7 :(得分:2)

为了调试这种情况,最好减少循环中的迭代次数。使用此代替while(true)

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

然后,您可以看到它以2开头并将值加倍,直到它导致溢出。

答案 8 :(得分:2)

我将使用8位数字进行说明,因为它可以在短空间内完全详细说明。十六进制数字以0x开头,而二进制数字以0b开头。

8位无符号整数的最大值为255(0xFF或0b11111111)。 如果添加1,通常会得到:256(0x100或0b100000000)。 但由于那个位数太多(9),超过了最大值,所以第一部分就会被删除,让你有效地为0(0x(1)00或0b(1)00000000,但是丢弃了1)。

所以当你的程序运行时,你会得到:

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

答案 9 :(得分:1)

类型int的最大小数字是 2147483648 (= 2 31 )。 0到2147483647 的所有小数文字都可能出现在int文字可能出现的任何地方,但文字 2147483648 可能只出现在一元否定运算符的操作数上。

如果整数加法溢出,则结果是数学和的低阶位,如某些足够大的二进制补码格式所示。如果发生溢出,则结果的符号与两个操作数值的数学和的符号不同。