Java如何处理溢出整数



现在signed_int最大值为2147483647,即2^31,1位为符号位,因此

当我运行long a = 2,147,483,647 + 1;

它给出a = -2,147,483,648作为答案。。这很好。但是,24*60*60*1000*1000 = 86400000000(实际上)。。。在java中,24*60*60*1000*1000 it equals to 500654080。。我知道这是因为在integer中溢出,但是什么处理导致了这个值,Java使用了什么逻辑来获得这个数字。我也参考了这里。

乘法像一样从左到右执行

    int x = 24 * 60;    
    x = x * 60;     
    x = x * 1000; 
    x = x * 1000;

前3个运算产生86400000,仍然适用于Integer.MAX_VALUE。但最后一个运算产生的86400000000是十六进制的0x141dd76000。4以上的字节被截断,得到0x1dd76000。如果我们打印

System.out.println(0x1dd76000);

结果将是

500654080

这是非常微妙的:在编写long a = 2147483647 + 1时,由于提供了int文字,因此首先使用int计算右手边。但在转换为long之前,它将循环到负值(由于溢出)。所以从int升级到long对你来说太晚了。

为了避免这种行为,你需要通过后缀L.来将至少一个论点提升为长文字

这适用于所有使用字面值的算术运算(即乘法):您需要将其中一个字面值提升为长类型。

你的乘法答案是500654080,这一事实可以从中看出

long n = 24L*60*60*1000*1000;
long m = n % 4294967296L; /* % is extracting the int part so m is 500654080 
                             n.b. 4294967296L is 2^32 (using OP notation, not XOR). */

这里发生的事情是,你正在使用int类型"昼夜不停"。是的,你正在丢失进位位,但这与乘法无关。

因为int的范围是-2147483648到2147483647。因此,当您继续添加数字并超过最大限制时,它会从最左边的数字开始增益,即-2147483648,因为它是一个循环。你已经在你的问题中提到了。

类似地,当您计算24*60*600*1000时,根据数学计算结果应为86400000000

但实际情况如下:

86400000000可以写为2147483647+2147483647%2147483647+214783647+21474833647+。。36次+500654080

因此,在将21474833647添加40次后,结果为0,然后留下500654080最终导致500654080

我希望你清楚。

在您的multiplicatoin中添加L。如果你加上L,那么它在长范围内乘以你,否则在溢出的整数范围内。试着像这样相乘。

24L*60*60*1000*1000

这给了你一个正确的答案。

整数的长度为32位。为了简单起见,让我们以一个4位长的数字为例。

最大正值为:

0111 = 7 (first bit is for sign; 0 means positive, 1 means negative)
0000 = 0

min负值为:

1111 = -8 (first bit is for sign)
1000 = -1

现在,如果我们称这种类型为fbit,那么fbit_max等于7。

fbit_max + 1 = -8
because bitwise 0111 + 1 = 1111

因此,fbit_minfbit_max的跨度为16。从-8到7。

如果您将类似7*10的东西相乘并将其存储在fbit中,结果将是:

fbit number = 7 * 10 (actually 70)
fbit number = 7 (to get to from zero to max) + 16 (min to max) + 16 (min to max) + 16 (min to max) + 15 (the rest)
fbit number = 6
24*60*60*1000*1000 = 86400000000

使用MOD如下:86400000000%214783648=500654080

最新更新