【Java】System.out.println(Integer.MAX_VALUE+1);背后的二进制故事与启示
導(dǎo)言
【說明】這里的代碼用Java語言描述,工具為Jshell,但原理是通用的。
迷幻語句送上—— System.out.println(Integer.MAX_VALUE+1);
執(zhí)行結(jié)果是什么?
Show me the answer……
OK……Look……
真是這個!!
原理分析
這個就要分析二進制了,我其實懶得在博客里分析一堆二進制,但這次我們看一下(大佬們可以略過~~)
先從二進制入手~~
(不講如何轉(zhuǎn)化原碼、反碼、補碼,這個都不會的話肯定不是程序員甚至可以說沒學(xué)過計算機……)
下圖為+2147483647(32位,2^31-1,int上限):
這是正數(shù)哦,原碼、反碼、補碼都是這個……
我們再看+1的:
相加,限于32位,會生成:
注意,這是補碼,所以說我們就想到了二進制中的“怪異數(shù)”,所以判定這個數(shù)的真值是2^(-31),也就是-2147483648。
用long就不溢出了吧?
盡管int只有32位,而long是64位,但——
答案是:No!
別急,我們接著看:
為什么long也會溢出呢?
代碼是這么執(zhí)行的:
int類型的Integer.MAX_VALUE+1,計算結(jié)果其實還是int類型的,這時將int轉(zhuǎn)型為long,瞬間擴到64位,但long會保留int本身的值,即符號位從32位移到64位,其余的第63位到第32位掛0。
要不然,如果符號位不移動,豈不是負數(shù)變正數(shù),即下面的不是-4?顯然不可能,擴容總不能丟失數(shù)據(jù)吧……
Integer.MAX_VALUE+2呢?
好吧,我們再做一遍二進制加法唄~~
我們姑且先認為是+1+1吧(這么算在這里比較方便),
基于+1的結(jié)果,-2147483648:
+1的二進制:
加法后:
這是補碼誒,轉(zhuǎn)反碼:
轉(zhuǎn)原碼:
我們知道了,是-(2^(-31)-1),即-2147483647,符合十進制運算,下面驗證一下:
好了,你說的我都懂,怎么能不變負數(shù)?
Good Question!
其實不難,在溢出之前轉(zhuǎn)成long就行~~
這樣就OK,嘿嘿……
你說的我懂了,問題是這東西有用?
有的,親~~
我們的程序在運行的時候,比如說
int i = 1000000; System.out.println(i*i);換成long:
這不是我們需要的答案啊!
那我們在能預(yù)判到的時候,就應(yīng)該直接在運算前(可能溢出前)轉(zhuǎn)型!!!
這就是我們要的~~
要注意什么……
我覺得主要是要注意在報錯之前自己對數(shù)值大小有個預(yù)判,比較熟練地了解Integer.MAX_VALUE和Long.MAX_VALUE的十進制和二進制,能做一個大致的判斷,若有溢出之嫌,可提前轉(zhuǎn)型。
BigInteger呢?
另,BigInteger的話,超大容量:
可惜構(gòu)造器好用的不多:
簡單使用我覺得String類型參數(shù)就很好使……
可以用Integer和Long的包裝類對象toString()進行轉(zhuǎn)化,nice!!
總結(jié)
以上是生活随笔為你收集整理的【Java】System.out.println(Integer.MAX_VALUE+1);背后的二进制故事与启示的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C语言】编写一个简单的学生成绩管理系统
- 下一篇: 理解题意优于一切(记洛谷P1426题WA