Java中整數(shù)基礎(chǔ)知識

原文鏈接 Java中整數(shù)基礎(chǔ)知識

最近做了一道題,非常有意思,題本身很簡單枷莉,但涉及到整數(shù)的最大值以及最小值击纬,當(dāng)寫測試用例的時(shí)候虐呻,卻犯了一個(gè)錯(cuò)誤绊困,發(fā)現(xiàn)最小整數(shù)并不是0xFFFFFFFF去团,我們來仔細(xì)看一下抡诞。

[圖片上傳失敗...(image-5c2114-1698067059650)]

整數(shù)基礎(chǔ)

Java中,整數(shù)都是有符號的土陪,最高位是符號位昼汗,0表示正數(shù),1表示負(fù)數(shù)鬼雀。有四種顷窒,byte,short取刃,int和long蹋肮。

  • byte 8位,-2^7 ~ 2^7 - 1璧疗,-128 ~ 127, 0x80 ~ 0x7F
  • short 16位,-2^15 ~ 2^15 - 1馁龟,-32768 ~ 32767, 0x8000 ~ 0x7FFF
  • int 32位崩侠,-2^31 ~ 2^31 -1,-2147483648 ~ 2147483647, 0x8000000 ~ 0x7FFFFFFF
System.out.println(String.format("Max byte %d, 0x%X, half 0x%X", Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE/2));
System.out.println(String.format("Min byte %d, 0x%X, half 0x%X", Byte.MIN_VALUE, Byte.MIN_VALUE, (byte)(Byte.MIN_VALUE/2)));
System.out.println(String.format("Max short %d, 0x%X, half 0x%X", Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE/2));
System.out.println(String.format("Min short %d, 0x%X, half 0x%X", Short.MIN_VALUE, Short.MIN_VALUE, (short) (Short.MIN_VALUE/2)));
System.out.println(String.format("Max Int %d, 0x%X, half 0x%X", Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE/2));
System.out.println(String.format("Min Int %d, 0x%X, half 0x%X", Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE/2));
        
// Outputs
//Max byte 127, 0x7F, half 0x3F
//Min byte -128, 0x80, half 0xC0
//Max short 32767, 0x7FFF, half 0x3FFF
//Min short -32768, 0x8000, half 0xC000
//Max Int 2147483647, 0x7FFFFFFF, half 0x3FFFFFFF
//Min Int -2147483648, 0x80000000, half 0xC0000000

細(xì)節(jié)和原理

值得注意的是坷檩,16進(jìn)制的數(shù)值與直覺預(yù)期并不一樣却音,特別是負(fù)數(shù)改抡。正數(shù)是一致的,比如int系瓢,一共是32位阿纤,最高位是符號,所以真正數(shù)值部分是31位夷陋,那么最大的int就是0x7FFFFFF欠拾。

但負(fù)數(shù),也即是最小的int骗绕,卻與直覺完全不一樣藐窄。按照直覺,負(fù)數(shù)最高位是1酬土,那最小的int應(yīng)該是0xFFFFFFFF啊荆忍,為何確是0x80000000呢?原因就是整數(shù)的編碼方式并不是直接的二進(jìn)制形式的撤缴,是以補(bǔ)碼的形式刹枉,也就是說在內(nèi)部實(shí)現(xiàn)中,用二進(jìn)制表示一個(gè)整數(shù)的時(shí)候屈呕,是以二進(jìn)制補(bǔ)碼形式(轉(zhuǎn)成二進(jìn)制后還要求其補(bǔ)碼嘶卧,才是真實(shí)的二進(jìn)制和16進(jìn)制形式)。

簡單來說凉袱,補(bǔ)碼是一種二進(jìn)制編碼形式芥吟,正數(shù)的補(bǔ)碼就是它的本身,而負(fù)數(shù)的補(bǔ)碼是其取反后加1专甩,可以參考百科上的定義钟鸵。

負(fù)數(shù)的轉(zhuǎn)換:原碼取反加1,即是補(bǔ)碼涤躲,補(bǔ)碼再轉(zhuǎn)補(bǔ)碼即得到原碼(也可以補(bǔ)碼減1再取反即是原碼)棺耍,符號位在轉(zhuǎn)換過程中一直不變。

注意:補(bǔ)碼的嚴(yán)謹(jǐn)說法是2的補(bǔ)碼(Twi's Complement)种樱,并不稱作二進(jìn)制補(bǔ)碼蒙袍。補(bǔ)碼是為了能用加法的方式來計(jì)算減法。因此原碼轉(zhuǎn)補(bǔ)碼時(shí)嫩挤,取反加1害幅,補(bǔ)碼求原碼時(shí)再求補(bǔ)碼,避免用減法(雖然減1后再取反也能求得原碼岂昭,但需要用到減法)以现。

非10進(jìn)制字面常量是補(bǔ)碼形式

在日常代碼中,為了方便,通常都用16進(jìn)制來寫一些整數(shù)常量邑遏,這里就特別要注意了佣赖。16進(jìn)制的字面常量,不會再進(jìn)行補(bǔ)碼轉(zhuǎn)換记盒,會當(dāng)成補(bǔ)碼直接使用憎蛤。

System.out.println(String.format("Literal %d, 0x%X", 0xffffffff, 0xffffffff));
//Literal -1, 0xFFFFFFFF

所以,你寫的0xFFFFFFFF是補(bǔ)碼形式纪吮,它的原碼是減1再取反俩檬,(32個(gè)1)減1,最低位變成0彬碱,前面31個(gè)1豆胸,再取反,就只剩下最后一位是1和最高位的符號位巷疼,因此是-1晚胡,注意符號位是不變的,在轉(zhuǎn)換過程中嚼沿。

而最小的整數(shù)是-2^31估盘,原碼 形式應(yīng)該是0x80000000,先取反變成了0xFFFFFFFF骡尽,再加1遣妥,符號位最高位不變的情況下,其余全變成了0攀细,所以是0x80000000箫踩。

最小整數(shù)

開篇時(shí)說了,當(dāng)時(shí)錯(cuò)誤的認(rèn)為0xFFFFFFFF是最小的整數(shù)谭贪,這里犯的第一個(gè)嚴(yán)重錯(cuò)誤是境钟,誤把二進(jìn)制的補(bǔ)碼當(dāng)成了原碼,代碼中的16進(jìn)制(二進(jìn)制)都是補(bǔ)碼形式的俭识,它的原碼是0x80000001即-1慨削。這個(gè)錯(cuò)誤是比較明顯的。

但另外的問題就是套媚,假如都是二進(jìn)制原碼的情況下缚态,為啥最小的整數(shù)是0x80000000而不是0xFFFFFFFFF。這是理解上的誤區(qū)堤瘤,整數(shù)的定義是玫芦,最高位是符號位,所以常規(guī)認(rèn)知是全是1的情況是最大的數(shù)宙橱,加上符號不就變成最小的了么姨俩?這是以10進(jìn)制思維蘸拔,也就是二進(jìn)制轉(zhuǎn)換成為10進(jìn)制后的想法师郑。計(jì)算機(jī)只認(rèn)識二進(jìn)制环葵,在最高位是1(負(fù)數(shù))的情況下,哪個(gè)數(shù)最斜γ帷张遭?當(dāng)然0x80000000最小啊,它除了符號位全是0地梨,肯定 小于0xFFFFFFFF菊卷,因此從二進(jìn)制的角度來理解,0x80000000是最小的整數(shù)宝剖。

而0xFFFFFFFF(原碼)則是第2小的負(fù)整數(shù)洁闰,最高位是符號位,其余31位全是1万细,它的補(bǔ)碼是0x80000001:

System.out.println(String.format("Literal %d 0x%X", 0x80000001, 0x80000001));
//Literal -2147483647 0x80000001

計(jì)算機(jī)中是以二進(jìn)制補(bǔ)碼來存儲整數(shù)的扑眉,所以要從計(jì)算機(jī)的角度來理解比較,就是要用二進(jìn)制的補(bǔ)碼來比較兩個(gè)數(shù)的大小赖钞。

再次強(qiáng)調(diào)腰素,我們寫的源碼當(dāng)中的二進(jìn)制(無論是字面常量,還是打印輸出)都是補(bǔ)碼形式雪营,計(jì)算機(jī)看到的也是補(bǔ)碼弓千,比較也是補(bǔ)碼,只有當(dāng)轉(zhuǎn)換成為10進(jìn)制時(shí)献起,才會還原為原碼并進(jìn)行10進(jìn)制轉(zhuǎn)換洋访。

由此得出,(注意谴餐,程序員眼睛看到的16進(jìn)制全是補(bǔ)碼形式):

  • 0x80000000是最小的負(fù)數(shù)姻政,原碼為0x80000000,-2^31
  • 0x80000001总寒,第2小的負(fù)數(shù)(最小的0x80000000再加上1)扶歪,原碼為0xFFFFFFFF,-(2^31-1)
  • 0xFFFFFFFF摄闸,是-1善镰,原碼為0x80000001。它是最大的負(fù)數(shù)(-1是最大的負(fù)數(shù))年枕。0xFFFFFFFF(全是1)肯定 最大啊炫欺,最高位是1,是負(fù)數(shù)熏兄,所以是最大的負(fù)數(shù)品洛。

一些有意思的值

Integer.MAX_VALUE + 1 = Integer.MIN_VALUE

按理說應(yīng)該溢出了树姨,但如果以16進(jìn)制去計(jì)算,就是這樣的結(jié)果:0x7FFFFFFF + 1 = 0x80000000

System.out.println(String.format("Max in %d (0x%X) + 1 = %d (0x%X)", Integer.MAX_VALUE, Integer.MAX_VALUE, (Integer.MAX_VALUE+1), (Integer.MAX_VALUE+1)));
// Max in 2147483647 (0x7FFFFFFF) + 1 = -2147483648 (0x80000000)

Integer.MIN_VALUE - 1 = Integer.MAX_VALUE

System.out.println(String.format("Min in %d (0x%X) - 1 = %d (0x%X)", Integer.MIN_VALUE, Integer.MIN_VALUE, (Integer.MIN_VALUE-1), (Integer.MIN_VALUE-1)));
//Min in -2147483648 (0x80000000) - 1 = 2147483647 (0x7FFFFFFF)

參考資料

原創(chuàng)不易转晰,打賞點(diǎn)贊士飒,在看查邢,收藏分享 總要有一個(gè)吧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酵幕,一起剝皮案震驚了整個(gè)濱河市扰藕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芳撒,老刑警劉巖邓深,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異番官,居然都是意外死亡庐完,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門徘熔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來门躯,“玉大人,你說我怎么就攤上這事酷师⊙攘梗” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵山孔,是天一觀的道長懂讯。 經(jīng)常有香客問我,道長台颠,這世上最難降的妖魔是什么褐望? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮串前,結(jié)果婚禮上瘫里,老公的妹妹穿的比我還像新娘。我一直安慰自己荡碾,他們只是感情好谨读,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坛吁,像睡著了一般劳殖。 火紅的嫁衣襯著肌膚如雪铐尚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天哆姻,我揣著相機(jī)與錄音宣增,去河邊找鬼。 笑死填具,一個(gè)胖子當(dāng)著我的面吹牛统舀,可吹牛的內(nèi)容都是我干的匆骗。 我是一名探鬼主播劳景,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肛宋,長吁一口氣:“原來是場噩夢啊……” “哼驱还!你這毒婦竟也來了躯砰?” 一聲冷哼從身側(cè)響起蹬挺,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤义锥,失蹤者是張志新(化名)和其女友劉穎红且,沒想到半個(gè)月后植袍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拯欧,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碉熄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年桨武,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锈津。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呀酸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出琼梆,到底是詐尸還是另有隱情性誉,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布茎杂,位于F島的核電站错览,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏煌往。R本人自食惡果不足惜倾哺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刽脖。 院中可真熱鬧羞海,春花似錦、人聲如沸曾棕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翘地。三九已至申尤,卻和暖如春癌幕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昧穿。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工勺远, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人时鸵。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓胶逢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饰潜。 傳聞我的和親對象是個(gè)殘疾皇子初坠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容