雜記 › 技術筆記 › 二進位、十六進位總是算不對?2/8/10/16 進位互轉方法

二進位、十六進位總是算不對?2/8/10/16 進位互轉方法

上個月排查一台發出告警的工控機。日誌裡那行寫的是 alarm=0x0E12,我掃了一眼,把 E12 當十進位讀成了「三千六百一十二」,又拿文件裡的位定義表從 bit0 數到 bit12,對上了一個根本不存在的項目,圍著錯誤的方向查了大半天。後來把 0x0E12 展開成 0000 1110 0001 0010 才看清:被設成 1 的是 bit1、bit4、bit9、bit10、bit11,加起來是 2+16+512+1024+2048 = 3602,跟「3612」差的就是我把十六進位的 1 當成十位那一格。值從來沒變,變的只是寫法。

一、進位只是同一個數換一種寫法

一個數值確定之後,用幾個數碼去書寫它是可以選的。基數決定了每一位能放幾個符號、以及進一位乘幾。

進位基數數碼程式碼裡的前綴你會在哪見到
二進位20 10b位元運算、暫存器、遮罩
八進位80-70o(舊寫法是前導 0)Linux 權限 chmod 755
十進位100-9無日常、日誌裡的計數值
十六進位160-9 A-F0x顏色、記憶體位址、協定位元組流

十六進位之所以在工程裡到處都是,是因為它和二進位是 4 位一組的整倍數關係:1 個十六進位位正好壓住 4 個二進位位,人看一眼 0xFF 就知道那是 8 位全 1。

二、手算只需要三招

  • 十進位轉別的:反覆除以基數取餘數,餘數倒著排。以 3756 轉十六進位為例:3756 ÷ 16 = 234 餘 12(C),234 ÷ 16 = 14 餘 10(A),14 ÷ 16 = 0 餘 14(E),倒排得 0xEAC。
  • 別的轉十進位:按位權展開。EAC = 14×256 + 10×16 + 12 = 3756,能回到原值說明上一步沒寫錯。
  • 二進位 ↔ 十六進位:從右往左每 4 位切一刀,逐組查表。3756 的二進位是 1110 1010 1100,三組分別是 E、A、C。

順便驗證一個不常見的:12345678 用 36 進位(0-9 加 A-Z)寫出來是 7CLZI,按權展開 7×36⁴ + 12×36³ + 21×36² + 35×36 + 18 = 11757312 + 559872 + 27216 + 1260 + 18 = 12345678,正好還原。短網址、訂單後綴那類「字母數字混合碼」基本上都是 36 進位。

三、常碰到的那幾個數,記住比現場換算快

十進位二進位十六進位八進位典型出處
2551111 1111FF377RGB 單通道上限、8 位全 1
4201101001001A4644chmod 644 的真實數值
4931111011011ED755chmod 755 的真實數值
40961 0000 0000 0000 0000100010000一頁記憶體的位元組數
6553516 個 1FFFF177777連接埠號上限、無號 16 位
1677721524 個 1FFFFFF7777777724 位色的白 #FFFFFF
214748364731 個 17FFFFFFF1777777777732 位有號整數上限,介面溢出的報錯值
429496729532 個 1FFFFFFFF37777777777無號 32 位、IPv4 廣播位址

八進位那一欄有個實用結論:755 和 493 是同一個權限的兩種寫法。設定檔裡存哪個都行,怕的是混著用——我看過同一段腳本一處寫 755、一處寫 493,diff 裡像改了兩遍。

四、我現在實際怎麼處理

  1. 先把日誌裡的原始寫法照抄下來,保留 0x、0b 前綴,不要憑記憶重敲,E12 那種事故一半來自手抄。
  2. 數值本身我會用進位轉換器算:選好來源進位,二、八、十、十六的結果同螢幕給出,省掉我一邊按計算機一邊對齊位數。位元遮罩要逐位勾的時候,我盯的是那個二進位輸出,不是十六進位。
  3. 位元組流要按字元看的時候用它另一個方向:文字轉成每個字元的進位編碼,A1 會得到 41 31,分隔符可選,擷取封包時對照協定表逐位元組核。
  4. 顏色那種六位十六進位我不再手拆。以前把 #FF8A00 拆成三段再除 255,經常漏掉進位,直接用顏色轉換把 HEX 和 RGB、HSL 對齊更省事。

如果只是想統一文字裡的全形半形或看 ASCII 值,文字編碼轉換更對口,它管的是字元層面,不是數值進位。

五、容易踩的三處

前綴和預設基數不一致。JavaScript 裡 parseInt('0755') 得到 755,parseInt('0755', 8) 才是 493;而字面量 0755 在嚴格模式和 ES Module 下直接拋 SyntaxError,八進位必須寫 0o755。同一份權限值,三種寫法三種結果,跨語言傳設定時務必寫全基數。

大數會先丟精度再談進位。雙精度浮點只能精確表示到 2⁵³−1 = 9007199254740991,再往上 9007199254740993 會被存成 ...992。這類數換算前得確認工具按 BigInt 走,否則十六進位看著正常、尾數已經錯了。

負數沒有「標準十六進位」。-1 寫成 FFFFFFFF 只在 32 位補數這個前提下成立,換 16 位就是 FFFF。進位轉換處理的是數值本身,位寬要自己帶上。

六、常見疑問

Q:為什麼電腦非要用二進位?

物理上兩個狀態最穩(高電位低電位),抗噪和實作成本都最低。八進位、十六進位不是給機器用的,是把幾十個 01 壓縮成人眼能掃的寫法。

Q:十六進位小數怎麼轉?

整數除基取餘,小數是乘基取整:0.5 × 16 = 8.0,所以 0.5 寫成 0.8。但 0.1 在任何以 2 為基的進位下都是無限循環的,這正是浮點誤差的來源之一,別指望換一種進位能消掉它。

Q:0xFF 和字串「FF」有區別嗎?

有。前者是數值字面量,後者是文字,要明確按 16 進位解析才能得到 255。日誌、JSON、設定檔裡的「十六進位」幾乎都是字串形態,這就是很多換算錯位的起點。

Q:為什麼最多到 36 進位?

36 剛好是 10 個數字加 26 個字母。再往上要引入大小寫區分(62 進位)或其他符號,可讀性和不區分大小寫的情境都會出問題。

Q:位元遮罩怎麼核對有沒有多勾一位?

把合計值轉回二進位,逐位和文件表對齊;兩邊位序(從 0 還是從 1 起數)確認一次。我做的是把 3602 展開成 0000 1110 0001 0010 對著表打勾,比反向把位值加起來更容易發現多出的那一位。

那台回報 0x0E12 的機器最後確認是編碼器異常加馬達過溫同時觸發,跟進位沒關係。但它讓我改掉一個習慣:凡是帶 0x、0o 的值,一律展開成二進位或十進位寫在註解裡,不靠腦內換算。人的十進位直覺是唯一會出錯的那一環。

📎 相關文章

PNG 壓了三遍只減 426 位元組:無損壓縮的真實邊界 2026-10-22 WebP 轉 PNG 後體積漲了幾倍:什麼時候必須轉,怎麼把漲幅壓住 2026-10-22 截圖縮到四分之一,小字糊成一團的三種原因 2026-10-22 同樣裁 300×300,頭像為什麼總偏右下角半格 2026-10-22 按每月 1.7 倍預估 18 個月,腳本和表格為什麼給出兩個數 2026-10-22