【Java】System.out.println(Integer.MAX_VALUE+1);背后的二进制故事与启示
导言
【说明】这里的代码用Java语言描述,工具为Jshell,但原理是通用的。
迷幻语句送上—— System.out.println(Integer.MAX_VALUE+1);
执行结果是什么?
Show me the answer……
OK……Look……
真是这个!!
原理分析
这个就要分析二进制了,我其实懒得在博客里分析一堆二进制,但这次我们看一下(大佬们可以略过~~)
先从二进制入手~~
(不讲如何转化原码、反码、补码,这个都不会的话肯定不是程序员甚至可以说没学过计算机……)
下图为+2147483647(32位,2^31-1,int上限):
这是正数哦,原码、反码、补码都是这个……
我们再看+1的:
相加,限于32位,会生成:
注意,这是补码,所以说我们就想到了二进制中的“怪异数”,所以判定这个数的真值是2^(-31),也就是-2147483648。
用long就不溢出了吧?
尽管int只有32位,而long是64位,但——
答案是:No!
别急,我们接着看:
为什么long也会溢出呢?
代码是这么执行的:
int类型的Integer.MAX_VALUE+1,计算结果其实还是int类型的,这时将int转型为long,瞬间扩到64位,但long会保留int本身的值,即符号位从32位移到64位,其余的第63位到第32位挂0。
要不然,如果符号位不移动,岂不是负数变正数,即下面的不是-4?显然不可能,扩容总不能丢失数据吧……
Integer.MAX_VALUE+2呢?
好吧,我们再做一遍二进制加法呗~~
我们姑且先认为是+1+1吧(这么算在这里比较方便),
基于+1的结果,-2147483648:
+1的二进制:
加法后:
这是补码诶,转反码:
转原码:
我们知道了,是-(2^(-31)-1),即-2147483647,符合十进制运算,下面验证一下:
好了,你说的我都懂,怎么能不变负数?
Good Question!
其实不难,在溢出之前转成long就行~~
这样就OK,嘿嘿……
你说的我懂了,问题是这东西有用?
有的,亲~~
我们的程序在运行的时候,比如说
int i = 1000000; System.out.println(i*i);换成long:
这不是我们需要的答案啊!
那我们在能预判到的时候,就应该直接在运算前(可能溢出前)转型!!!
这就是我们要的~~
要注意什么……
我觉得主要是要注意在报错之前自己对数值大小有个预判,比较熟练地了解Integer.MAX_VALUE和Long.MAX_VALUE的十进制和二进制,能做一个大致的判断,若有溢出之嫌,可提前转型。
BigInteger呢?
另,BigInteger的话,超大容量:
可惜构造器好用的不多:
简单使用我觉得String类型参数就很好使……
可以用Integer和Long的包装类对象toString()进行转化,nice!!
总结
以上是生活随笔为你收集整理的【Java】System.out.println(Integer.MAX_VALUE+1);背后的二进制故事与启示的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 【C语言】编写一个简单的学生成绩管理系统
- 下一篇: 理解题意优于一切(记洛谷P1426题WA