与你预期结果不符的原因,其实是2147483647为int类型的最大值。
int最高只能等于这个数字,那么超过的部分的处理方式是什么呢?我用JDK11的JShell临时做了一个验证,Integer.MAX__VALUE = 2147483647;当Integer.MAX_VALUE + 1的时候,可以发现,这个时候数值是 -2147483648,即 -Integer.MAX_VALUE - 1 。
int j = Integer.MAX_VALUE + 1;
//j = -214783648, 即:- Integer.MAX_VALUE - 1.
但是,当我们继续在Integer.MAX_VALUE上面累加的时候,数值开始在负数范围内增大,变为-214783647,-214783646等。
原因是什么呢?我们知道,int占用四字节,并且最高位作为符号标志,为1的时候是负数,零的时候是正数,Integer.MAX_VALUE是当最高位为0,其他位均为1的时候,最大的在int范围内的正整数。
-214783648这个数值,就是在4字节int值全部为1的时候,由于首位表示符号,他是一个负数,由于和上一个数值相比,他的绝对值多了一。
我们不看四字节,以4位二进制举例,他和4字节二进制原理是一样的:
首先来说,这个四位二进制的最大正整数应该是多少呢:最高位为0,其余都是一,这是最大的正整数:0111 1111,记住这个数值,那么:
0111 1111 + 1
会发生什么呢:
1000 0000
变成了这样,也就是说,整体变为负数,这个数值就是负的,负数的二进制转10,需要符号位不变,其余取反并在末尾加一:
1000 0000 =取反= 0111 1111 + 1 = 1000 0000
,决对值增大了一,这就是Integer.MAX_VALUE + 1的时候的结果。那么继续累加下去呢?
1000 0000 + 1 = 1000 0001
这个数值就是负的,负数的二进制转10,需要符号位不变,其余取反并在末尾加一,即
1000 0001 =取反= 0111 1110 + 1 = 0111 1111
很明显,这个数值是原本的最大的8位整数值。但是他的绝对值和上一个数值想比减少了1,这也是Integer.MAX_VALUE + 2 后变成 Integer.MAX_VALUE本身负数的原理,以此类推,我们可以预见,继续增加数值,那么他会继续在负数的范围内增大。
语句:i *= 214783647 等价于 i = i * Integer.MAX_VALUE
即:i = Integer.MAX_VALUE * Integer.MAX_VALUE。
很明显,这个结果远超了最大值,我们能够猜测到,这四字节二进制会反复在正数和负数之间相互变化,一直到计算完成,你可以手动算下,下面是我用win10计算器得到的结果:
你可以看到,结果超过了int的范围,因此java只取了最末的4byte,即:
0000 0000 ,0000 0000 ,0000 0000, 0000 0001
因此,最终的结果变成了1.
综上所述,*=运算没有问题,它正如你期望那样的运行,只不过结果超过了int的最大值,因此你看到了1.
题主得到了问题的答案,并且进行了拓展,我在这里贴出题主的观点:我今上午也弄明白了,比如4*3,在计算的时候是
(((( [((((4+1)+1)+1)+1)] +1)+1)+1)+1)
在每一次+1时都要考虑结果溢出,如果溢出就按int最小数计算,继续+1。
昨天出这个问题是因为我直接把两数相乘,然后计算溢出的结果,而实际上应该考虑相加过程中出现的溢出情况。
同时也找到了2147483647乘以0~2147483647时,溢出后结果的规律:
2147483647*a 时,如果a是偶数,则溢出后的结果为-a;
如果a是奇数,则溢出后的结果为2147483647 - (a-1)
经四次不同数验证,结果正确。
2147483647*1时,结果为2147483647 - (1-1) = 2147483647
2147483647*2时,结果为-2
2147483647*3时,结果为2147483647 - (3-1) = 2147483645
2147483647*4时,结果为-4
2147483647*5时,结果为2147483647 - (5-1) = 2147483643
2147483647*6时,结果为-6
……
2147483647*2147483647时,结果为2147483647 - (2147483647-1) = 2147483647 - 2147483646 = 1
// 代码在这里// 如果b是偶数,溢出后的结果就等于 -b// 如果b是奇数,溢出后的结果就等于 2147483647-(b-1)public class Test{
public static void main(String[] args){
int a = 2147483647;
int b = 1;
System.out.println(a * b);
int result = simulationMultiply(a, b);
System.out.println(result);
}
public static int simulationMultiply(int num1, int num2){
int result = num1;
int count = num2;
// 这里的for 最好加上括号,以免引起误解。 for(int i = 1; i < count; i++){
for(int j = 0; j < num1; j++){
result += 1;
}
}
return result;
}
}