二進位制補碼計算工具(有符號整數二進位制轉換)
將有符號十進位制整數轉換為8/16/32/64位的二進位制補碼錶示,或進行反向轉換。同時顯示無符號整數解釋、十六進位制表示,並檢測超出範圍的輸入。
使用提示
- 8位有符號整數的範圍是-128到127。可以嘗試先輸入127再輸入128,觀察溢位邊界——128無法容納並會觸發範圍錯誤,而這正是原本會迴繞到-128的邊界點。
- 「無符號十進位制」這一行是將同一位元序列不作為符號位處理而直接解讀得到的值。與有符號那一行對比,能立刻看出有符號與無符號解釋之間的差異。
- 二進位制輸入的位數必須與所選位寬完全一致——8位輸入8位數字,16位輸入16位數字,以此類推。
- 64位的計算在內部使用BigInt而非JavaScript的Number型別,因此接近2^63的數值也能無精度損失地轉換。
- 本工具也可用於理解C語言、Java等語言中整數溢位的行為,它們的int(32位)、long(64位)型別都會在同樣的邊界處發生迴繞。
常見問題
原碼錶示和反碼錶示都會產生兩種不同的零的位元模式(「+0」和「-0」),這會使比較和運算電路變得複雜。補碼錶示的零隻有一種位元模式,而且同樣重要的是,用於加法的加法器電路也可以直接用於減法。這兩個特性讓CPU設計者能夠簡化算術邏輯單元,這正是幾乎所有現代處理器內部都使用補碼來表示有符號整數的原因。
-128到127。由於最高位被保留作為符號位,正數一側只能表示128種不同的模式(0到127),而負數一側可以表示128種不同的值(-1到-128),因為補碼的零隻佔用一種位元模式,多出的一種模式被分配給了負數一側,這就是範圍不對稱的原因。
反碼只需將正數的每一位取反即可得到負數。補碼則在取反的基礎上再加1。這多出的一步消除了反碼固有的「雙零問題」(00000000表示「+0」,11111111表示「-0」),這也是補碼成為標準表示方式的原因。
因為位寬是固定的,任何超出可表示範圍的運算結果都會導致高位被截斷,從而改變了符號位的含義。例如,對8位有符號最大值127加1會得到位元模式10000000,按有符號規則解讀為-128。超過上限就會迴繞到下限,這種違反直覺的跳變正是溢位的本質。
位元模式本身不會改變,但由於不再將最高位當作符號位,每一位都只貢獻其常規的位權值。例如8位位元模式11111011,按有符號解讀為-5,但按無符號解讀則為251。當你把一個原本按有符號處理的值用於像C語言unsigned int這樣的「無符號」型別時,實際上就會發生這種重新解釋。
閒話 ― 為什麼計算機使用二進位制補碼
二進位制補碼並不是表示負數的唯一方式。歷史上還使用過原碼錶示(僅將最高位當作符號標誌)和反碼錶示(簡單地將正數的每一位取反)。這兩種方式都有一個共同的缺陷:會出現兩種不同的零的位元模式,即「+0」和「-0」,這使得比較邏輯和電路設計變得複雜。而二進位制補碼完全避免了這個「雙零問題」——每一種位元模式都唯一對應一個整數值。
補碼更大的優勢在於,用於加法的同一套加法器電路也可以直接用於減法,因為減去一個數等價於加上它的補碼。CPU無需判斷某個值是正數還是負數,只需將位元模式相加即可得到正確結果。這使得算術邏輯單元(ALU)可以省去專門的減法電路,這也是幾乎所有現代CPU架構都採用補碼來表示有符號整數的原因。
整數溢位正是這種表示方式的直接結果。8位有符號最大值127(01111111)加1後,位元模式簡單地進位為10000000——若按有符號方式解讀,這就是-128。在C語言中,有符號整數溢位在技術上屬於「未定義行為」,編譯器最佳化可能在這個邊界附近產生出人意料的結果,因此在實際生產程式碼中需要格外謹慎。相比之下,Java明確規定溢位會靜默地迴繞,這也是一個有趣的例子,說明即使底層位元表示完全相同,不同語言之間的行為保證也可能大相逕庭。