奇怪的 -2147483648;为什么Java中 2147483647加一是-2147483648

发现

Java int 范围 -2147483648 ~ 2147483647

执行一下代码发现:

int a = 2147483647;
int b = a + 1; 
int c = b - 1;
sout(b) // b = -2147483648
sout(c) // c = 2147483647

b 是 -2147483648
c 是 2147483647

似乎是一个循环?

为什么

原码反码补码

上边这个链接看完知道,cpu二进制计算不对原码进行计算, 而是对补码进行计算。
就是说计算机的运算方式并不完全是按照人类的计算方式来的即 1+1有时候不是等于2
其实应该是初学时就应该研究的问题。只是在学校没好好学

在这个基础上

补码运算

十进制八进制原码补码
21474836477FFFFFFF0111 1111 1111 1111 1111 1111 1111 11110111 1111 1111 1111 1111 1111 1111 1111
110000 0000 0000 0000 0000 0000 0000 00010000 0000 0000 0000 0000 0000 0000 0001
-1FFFFFFFF1000 0000 0000 0000 0000 0000 0000 00011111 1111 1111 1111 1111 1111 1111 1111
-2147483647800000011111 1111 1111 1111 1111 1111 1111 11111000 0000 0000 0000 0000 0000 0000 0001
-21474836488000000032位无法表示1000 0000 0000 0000 0000 0000 0000 0000

1. 首位为符号位 “0 - 正”, “ 1 - 负”
2. 正数的补码就是它本身
3. 负数的补码是 原码符号位不变,各位取反,末尾加1

回到开始的发现
java中 int 是 32位 ,也就是说最多最多可以保存二进制32位,如果计算所过程中超出这个范围那么计算机的计算方式就与人类不同,即可能发生 1+1不等于2的问题.
这里的范围看JAVA Integer.java 源码

    /**
     * A constant holding the minimum value an {@code int} can
     * have, -2<sup>31</sup>.
     */
    @Native public static final int   MIN_VALUE = 0x80000000;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    @Native public static final int   MAX_VALUE = 0x7fffffff;

转成补码的意义对于计算机来说就是,只有 加 运算
比如 1 - 1 就是:1 的补码加上 -1 的补码
32位运算, 即:

0000 0000 0000 0000 0000 0000 0000 0001
+
1111 1111 1111 1111 1111 1111 1111 1111

=
1 0000 0000 0000 0000 0000 0000 0000 0000
只能保存 32bit 的数据,所以 1 被丢弃
上式

=
0000 0000 0000 0000 0000 0000 0000 0000

这样计算机就可以仅通过加法且忽略符号直接计算出结果

明白了这些,现在再计算一下 JAVA 中 int 的 2147483647 + 1
首先两者转换成二进制原码,然后得出其补码,正数的补码是他本身
即:

0111 1111 1111 1111 1111 1111 1111 1111
+
0000 0000 0000 0000 0000 0000 0000 0001

=
1000 0000 0000 0000 0000 0000 0000 0000

这个数字就非常特别了,零的机内表示形式

正零 = 0000 0000 0000 0000 0000 0000 0000 0000
负零 = 1000 0000 0000 0000 0000 0000 0000 0000

也就是说 补码32位表示的整数范围要比原码表示范围多一个数 即 -0

所以为了不浪费资源把这个[1000 0000 0000 0000 0000 0000 0000 0000]人为规定为 -2147483648,但-2147483648在32位中是没有补码的。
同理,8位 [1000 0000] 人为规定为 -128

那么,最后再计算一个 -2147483648 -1
即,

-2147483648 + (-1)
=
1000 0000 0000 0000 0000 0000 0000 0000
+
1111 1111 1111 1111 1111 1111 1111 1111

=
1 0111 1111 1111 1111 1111 1111 1111 1111
最高位溢出,舍掉

=
0111 1111 1111 1111 1111 1111 1111 1111

那么,最高位是0 是正数,正数的原码和补码一致,所以他的十进制数就是:2147483647


破案了

也就是说,int 类型的数据被设计成只能存储二进制32bit的数据,由于计算机存储数据是通过补码形式,且补码表示整数范围比原码多一个-0,导致int类型的表示范围是 -2147483648 ~ 2147483647。又因为int类型的32位数据限制最高位是符号位,溢出的数据被丢弃,导致数据精度丢失,表现出来的现象就是 2147483647加一是-2147483648

以上为个人理解的思路,在查资料过程中发现已经有大神详细的说明了此处的疑惑:-2147483648~2147483647–深入计算机内存运算了解二进制本质

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值