二进制转十进制(及十六进制):分步详解
二进制转十进制的方法是:把每一位乘以它的位权,再把结果相加。位权是 2 的幂,从右往左依次翻倍:1、2、4、8、16,以此类推。例如,二进制数 1011 等于 1×8 + 0×4 + 1×2 + 1×1 = 8 + 0 + 2 + 1 = 11。
免费试用:整数进制转换器 免费使用,无需注册账号。
本文介绍二进制转十进制的两种方法、如何反过来把十进制转二进制、什么是十六进制以及程序员为什么使用它,还有如何不借助计算器在二进制、十六进制和八进制之间转换。下面的每个示例都已用代码验证。阅读时如果想核对自己的数字,可以把它们粘贴到免费的二进制转换器中。
如何读二进制:位权
二进制码是只用 0 和 1 两个符号表示的信息。计算机使用二进制,是因为其电路只有两种状态,比如低电压和高电压。每一个二进制数字称为一个位(bit),8 位组成一个字节(byte)。
二进制和十进制一样,是一种位置记数法。在十进制中,每一位的值是其右边一位的 10 倍(个位、十位、百位)。在二进制中,每一位的值是其右边一位的 2 倍:
| 位置(从右数) | 第 8 位 | 第 7 位 | 第 6 位 | 第 5 位 | 第 4 位 | 第 3 位 | 第 2 位 | 第 1 位 |
|---|---|---|---|---|---|---|---|---|
| 2 的幂 | 2⁷ | 2⁶ | 2⁵ | 2⁴ | 2³ | 2² | 2¹ | 2⁰ |
| 位权 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
1 表示“计入这个位权”,0 表示“跳过”。
二进制转十进制:分步方法
方法一:位权相加
以二进制数 11010110 为例。在每一位下方写出位权,保留位为 1 的那些,再把它们相加:
| 位 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| 位权 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
| 位 × 位权 | 128 | 64 | 0 | 16 | 0 | 4 | 2 | 0 |
128 + 64 + 16 + 4 + 2 = 214。所以 11010110₂ = 214₁₀。右下角的小数字用于在进制不明确时标明进制。
方法二:乘 2 再加
这种方法不需要表格。从 0 开始,从左到右依次读取每一位:把当前累计值乘以 2,再加上当前这一位。
以 101101 为例:
- 0 × 2 + 1 = 1
- 1 × 2 + 0 = 2
- 2 × 2 + 1 = 5
- 5 × 2 + 1 = 11
- 11 × 2 + 0 = 22
- 22 × 2 + 1 = 45
所以 101101₂ = 45。用方法一验证:32 + 8 + 4 + 1 = 45。
十进制转二进制
除 2 取余法
把数字除以 2,记下余数(0 或 1),再用商重复这一过程,直到商为 0。然后从下往上读取余数。以 156 为例:
| 除法 | 商 | 余数 |
|---|---|---|
| 156 ÷ 2 | 78 | 0 |
| 78 ÷ 2 | 39 | 0 |
| 39 ÷ 2 | 19 | 1 |
| 19 ÷ 2 | 9 | 1 |
| 9 ÷ 2 | 4 | 1 |
| 4 ÷ 2 | 2 | 0 |
| 2 ÷ 2 | 1 | 0 |
| 1 ÷ 2 | 0 | 1 |
从下往上读,得到 156 = 10011100₂。验证:128 + 16 + 8 + 4 = 156。最常见的错误是从上往下读余数,这样得到的位顺序正好相反。
减去 2 的幂
对于较小的数,更快的做法往往是取不超过它的最大 2 的幂,减去后重复。以 100 为例:先取 64(100 − 64 = 36),然后是 32(36 − 32 = 4),再是 4(4 − 4 = 0)。在 64、32 和 4 下方写 1,其余位置写 0:100 = 1100100₂。
什么是十六进制?
十六进制(hex)是以 16 为基数的进制。它需要 16 个数字,所以在 0–9 之后用字母 A–F 表示 10 到 15:A = 10,B = 11,C = 12,D = 13,E = 14,F = 15。每一位的值是其右边一位的 16 倍:1、16、256、4,096,以此类推。
程序员使用十六进制,是因为它与二进制严格对应。四个位有 16 种可能的组合(0000 到 1111),所以一个十六进制数字正好是 4 位,两个十六进制数字正好是一个字节。最大的字节 11111111 在十六进制中就是 FF,而在十进制中是 255,从这个数看不出位模式。这就是内存地址、颜色代码、MAC 地址和 IPv6 地址都用十六进制书写的原因。
十六进制转十进制
使用同样的位权法,只是换成 16 的幂,并把字母替换为对应的值:
- 2F = 2 × 16 + 15 × 1 = 32 + 15 = 47
- 1A3 = 1 × 256 + 10 × 16 + 3 × 1 = 256 + 160 + 3 = 419
十进制转十六进制
十进制转十六进制与十进制转二进制的做法相同,只是改为除以 16。10 到 15 的余数写成字母 A 到 F。以 1000 为例:
| 除法 | 商 | 余数 |
|---|---|---|
| 1000 ÷ 16 | 62 | 8 |
| 62 ÷ 16 | 3 | 14 = E |
| 3 ÷ 16 | 0 | 3 |
从下往上读余数,得到 1000 = 3E8₁₆。验证:3 × 256 + 14 × 16 + 8 = 768 + 224 + 8 = 1000。
二进制转十六进制:每四位一组
由于一个十六进制数字就是四位,二进制转十六进制完全不需要计算。从右边开始,把二进制数每四位分成一组(称为半字节,nibble),再按下表替换每一组:
| 二进制 | 十六进制 | 十进制 | 二进制 | 十六进制 | 十进制 |
|---|---|---|---|---|---|
| 0000 | 0 | 0 | 1000 | 8 | 8 |
| 0001 | 1 | 1 | 1001 | 9 | 9 |
| 0010 | 2 | 2 | 1010 | A | 10 |
| 0011 | 3 | 3 | 1011 | B | 11 |
| 0100 | 4 | 4 | 1100 | C | 12 |
| 0101 | 5 | 5 | 1101 | D | 13 |
| 0110 | 6 | 6 | 1110 | E | 14 |
| 0111 | 7 | 7 | 1111 | F | 15 |
示例:
- 11010110 → 1101 0110 → D6(D6 = 13 × 16 + 6 = 214,与上文是同一个数)
- 101101 → 左侧补零为 0010 1101 → 2D(= 45)
十六进制转二进制则反过来:把每个十六进制数字替换为对应的四位。3E8 → 0011 1110 1000 → 去掉前导零后为 1111101000。
八进制简介
八进制以 8 为基数,使用数字 0–7。它的原理与十六进制相同,只是三位一组,因为 2³ = 8。如今它最常见的用途是 Unix 文件权限。在 chmod 755 中,每个数字代表三个权限位(读、写、执行):
- 7 = 111 = rwx
- 5 = 101 = r-x
- 5 = 101 = r-x
所以八进制的 755 对应位模式 111 101 101,即十进制的 493。Chmod 计算器可以把勾选的权限转换成八进制数,也可以显示 755 这样的数字设置了哪些权限。
这些转换在哪里会用到
- IPv4 地址。 四个数字各占一个字节。192.168.1.10 的二进制是 11000000.10101000.00000001.00001010;192 = 128 + 64。
- 网页颜色。 像 #FF8800 这样的十六进制颜色由三个字节组成:红色 FF = 255,绿色 88 = 8 × 16 + 8 = 136,蓝色 00 = 0,所以它等于 rgb(255, 136, 0)。颜色转换器可以对任意颜色进行这种转换。
- 文本。 在 ASCII 和 Unicode 中,大写字母 A 的编码是 65,即十六进制的 0x41、二进制的 01000001。小写字母 a 是 97(0x61,01100001);两者相差 32,只差一个位。
前缀:0b、0x 和 0o
在代码中,前缀告诉编译器一个数字字面量使用哪种进制:
| 前缀 | 进制 | 示例 | 十进制值 |
|---|---|---|---|
0b |
二进制(2) | 0b1011 |
11 |
0o |
八进制(8) | 0o755 |
493 |
0x |
十六进制(16) | 0x3E8 |
1000 |
0x 几乎适用于所有语言。Python、JavaScript、Java、C# 和 C++ 都支持 0b。Python 和 JavaScript 使用 0o,而 C 和 C++ 只用一个前导零表示八进制,所以 C 中的 0755 是 493,而不是 755。
大多数语言也能帮你转换字符串:
# Python
int("1011", 2) # 11
bin(156) # '0b10011100'
hex(1000) # '0x3e8'
int("3E8", 16) # 1000
// JavaScript
parseInt("1011", 2) // 11
(1000).toString(16) // "3e8"
Number("0b1011") // 11
有一个陷阱:在 JavaScript 中,parseInt("0b1011") 返回 0,因为 parseInt 遇到第一个无法识别的字符就会停止,而且它不认识 0b 前缀。应去掉前缀并传入基数(radix),详见 MDN 的 parseInt 参考文档。
关于负数
计算机通常用补码(two's complement)存储负整数。要用 8 位表示 −5,先从 5 = 00000101 开始,把每一位取反得到 11111010,再加 1:11111011。如果按无符号数读取,同一个位模式是 251(256 − 5),即十六进制的 FB。这就是为什么同一个字节既可以表示 −5,也可以表示 251,取决于程序是否把它当作有符号数。
二进制、十进制、八进制和十六进制对照表
| 十进制 | 二进制 | 八进制 | 十六进制 |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 |
| 2 | 10 | 2 | 2 |
| 3 | 11 | 3 | 3 |
| 4 | 100 | 4 | 4 |
| 5 | 101 | 5 | 5 |
| 6 | 110 | 6 | 6 |
| 7 | 111 | 7 | 7 |
| 8 | 1000 | 10 | 8 |
| 9 | 1001 | 11 | 9 |
| 10 | 1010 | 12 | A |
| 11 | 1011 | 13 | B |
| 12 | 1100 | 14 | C |
| 13 | 1101 | 15 | D |
| 14 | 1110 | 16 | E |
| 15 | 1111 | 17 | F |
| 16 | 10000 | 20 | 10 |
| 32 | 100000 | 40 | 20 |
| 64 | 1000000 | 100 | 40 |
| 100 | 1100100 | 144 | 64 |
| 127 | 1111111 | 177 | 7F |
| 128 | 10000000 | 200 | 80 |
| 255 | 11111111 | 377 | FF |
| 256 | 100000000 | 400 | 100 |
用二进制转换器转换任意进制
免费的二进制转换器直接在浏览器中运行。输入一个数字并设置它的进制,即可同时看到该值的二进制、八进制、十进制和十六进制形式,外加一个自定义输出进制。
- 支持 2 到 64 的任意进制,输入和自定义输出均可。
- 前缀和大写: 当
0b、0o和0x与输入进制匹配时可以直接使用;在 36 进制以内也接受FF这样的大写字母。超过 36 进制时,小写和大写字母是不同的数字。 - 清晰的错误提示: 输入无效数字(比如二进制中的 2)时,会显示该进制允许哪些数字;在 10 进制下使用
0x前缀时,会提示你把进制切换为 16。 - 位长度: 显示该数字需要多少位,例如 42(101010)需要 6 位。
- 大数: 能精确转换非常长的整数,例如写成一个数字的完整 128 位 IPv6 地址。
需要了解的几点限制:它只转换非负整数,所以负号或小数点会被拒绝;十六进制输出为小写且不带前导零;“Base64 (64)” 这一行是使用数字 0–9、a–z、A–Z、+ 和 / 的 64 进制数,而不是 Base64 文本编码。
常见问题
8 位最多能存储多大的数?
255,二进制写作 11111111,十六进制写作 FF。八位共有 2⁸ = 256 种不同组合,覆盖 0 到 255。十六位可达 65,535,每多一位,范围就翻一倍。
为什么程序员用十六进制而不是十进制?
因为每个十六进制数字正好对应四位,可以直接从十六进制数字读出位模式。一个字节总是两个十六进制数字(00 到 FF)。十进制没有这种对应关系:255 和 256 在十进制中看起来相近,但在二进制中分别是 11111111 和 100000000。
如何把二进制小数转换为十进制?
二进制小数点后的各位分别代表 1/2、1/4、1/8,以此类推。所以 101.11₂ = 4 + 1 + 0.5 + 0.25 = 5.75。许多十进制小数(例如 0.1)没有精确的二进制表示,这就是为什么在大多数编程语言中 0.1 + 0.2 并不严格等于 0.3。二进制转换器只处理整数。
二进制码和 ASCII 是一回事吗?
不是。二进制是一种数制;ASCII 是一张为每个字符分配编号的表。字母 A 的 ASCII 码是 65,这个数字以位 01000001 的形式存储。
免费试用:整数进制转换器 免费使用,无需注册账号。