数值越界oracle_Java int 类型数值越界引发的思考

今天在重写Twitter 的分布式ID生成算法 sonw flake算法时,遇到一个问题,即一个整数在多次相乘后,输出的结果是0!对应的测试程序如下:

1

2

3

4

5

6int a = 1;

System.out.println(a);

for (int i =2;i<42;++i) {

a = a*2;

}

System.out.println(a);

后来思考了一下才反应过来,这个相乘的结果,远超过了Java int类型可以表示的范围。Java int类型可以表示的范围才是-$2^{31}$到$2^{31}$-1。

但是为什么输出结果是0呢?

因为计算机在存储数据时,最高位表示的是符号位,0表示正数,1表示负数,并且计算机中的数据使用补码来表示的。正数的补码是其本身,而负数的补码则是其反码加1(不包括符号位).

因为在执行“a = a*2”,当a=$2^{31}$时,在计算机中的表示已经变成变成了“10000000 00000000 00000000 00000000”,然后计算机在读取这个值的时候,就会把它当成负数来读,然后对应的值就是最小负数:-2147483648。

接下来,当执行到a=$2^{32}$,理论上值已经变成“1 00000000 00000000 00000000 00000000”,即33位,但是计算机在读取int类型时,只会读取32位,因此会舍弃掉最前面的“1”,因此读出来的结果就是0.

下面以short类型举例,说明一下数字在计算机中二进制的存储方式:

最小的负整数 -32768        计算机中二进制标示:10000000   00000000

最大的负整数-1      计算机中二进制标示:11111111  11111111

0           计算机中二进制标示:00000000  0000000

最小的正整数 1                 计算机中二进制标示: 00000000 00000001

最大的正整数:32767    计算机中二进制标示: 01111111  11111111

最小负整数-32768加1之后,在计算机中的表示就是:10000000 00000001,对应的值就是- $ (2^{15} $ -1),即-32767。然后一直加1,直到11111111 11111111,对应的值就是-1,再加1,就变成了1 00000000 00000000,即17位,而short类型只读取16位,所以-1+1=0。00000000 00000000一直加1,加到01111111 11111111,就变成了short类型的最大整数32767。再加1,就变成了10000000 00000000,即最小负数:-32768。对应的循环图如下:

理解了这些之后就不难明白,为什么上一段程序的运行结果是0了。平时还是要多温故基础知识,否则很可能在一些不起眼的地方栽了坑。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值