现在位置: 首页 > 计算机组成原理 > 正文

进制转换 -- 二进制、十进制、十六进制

本讲你将掌握三种进制之间的转换方法,并理解十六进制为什么是二进制的「最佳缩写」。


生活化类比:多套计数系统

不同进制就像不同的「度量衡」。

人类习惯十进制,就像习惯用「米」来量身高。

计算机使用二进制,就像用「开关状态」来思考。

而十六进制,则是工程师的「速记符号」——用更短的方式表达冗长的二进制。

举个例子:「RUNOOB」这个词如果在三种「语言」中表达:

  • 十进制的人类语言:82 85 78 79 79 66
  • 二进制的机器语言:01010010 01010101 01001110 01001111 01001111 01000010
  • 十六进制的简写:52 55 4E 4F 4F 42

同样是一句话,二进制的表达长度是十六进制的 4 倍。

这就是我们需要学习进制转换的原因。


进制的本质:按权展开

所有进制的原理完全相同——每个位置上的数字乘以基数的幂,然后全部加起来

以数字 42 为例,看它在三种进制下分别如何被理解:

进制基数可用数字表示按权展开
十进制100 ~ 9424 x 101 + 2 x 100 = 42
二进制20, 11010101x25+0x24+1x23+0x22+1x21+0x20 = 42
十六进制160~9, A~F2A2 x 161 + 10 x 160 = 42

关键规律:进制的「基数」决定了每一位的权重

十进制基数 10,个位权重 100=1,十位 101=10,百位 102=100。

二进制基数 2,从右往左权重为 1, 2, 4, 8, 16, 32, 64, 128。

十六进制基数 16,从右往左权重为 1, 16, 256, 4096。

理解了「按权展开」,所有进制转换都变得简单了。你需要记住的只有一句话:每位数字 x 基数^位置编号,然后求和。


方法一:十进制转二进制(除 2 取余法)

假设你要把十进制的 42 转为二进制。

方法很机械:

  1. 用 42 除以 2,商 21 余 0
  2. 用 21 除以 2,商 10 余 1
  3. 用 10 除以 2,商 5 余 0
  4. 用 5 除以 2,商 2 余 1
  5. 用 2 除以 2,商 1 余 0
  6. 用 1 除以 2,商 0 余 1
  7. 从下往上读余数:101010
42 ÷ 2 = 210 ← (最低位)
21 ÷ 2 = 101
10 ÷ 2 = 50
5 ÷ 2 = 21
2 ÷ 2 = 10
1 ÷ 2 = 01 ← (最高位)
结果:从下往上读余数 = 101010

为什么这个方法有效?

二进制的本质是:N = d0x20 + d1x21 + d2x22 + ...

当 N 除以 2 时,余数就是 d0(最低位),商继续除 2 得到下一位。

这个逻辑和小学学过的「十进制除 10 取个位」完全一样。


方法二:二进制转十进制(按权展开法)

从二进制转回十进制更简单——直接按权重加起来。

二进制 101010(从右往左编号位置 0~5):

位置543210
二进制位101010
权重 (2^n)32168421
位 x 权重1x320x161x80x41x20x1

1x32 + 0x16 + 1x8 + 0x4 + 1x2 + 0x1 = 42


十六进制:二进制的「速记符号」

二进制的最大问题是写起来太长

一个 8 位的值要写 8 个数字,32 位则要写 32 个数字。

这既不便于人类阅读,也容易出错。

十六进制解决了这个问题,因为一个重要的数学巧合:

24 = 16  →  每 4 个二进制位正好对应 1 个十六进制位

4 位二进制与 1 位十六进制的映射表

二进制 (4位)十进制十六进制二进制 (4位)十进制十六进制
000000100088
000111100199
001022101010A
001133101111B
010044110012C
010155110113D
011066111014E
011177111115F

这张表是十六进制的核心。

熟记之后,任何二进制转十六进制都是「查表取字」的机械操作。

示例:二进制 11111111 转十六进制

8 位二进制分为两组,每组 4 位:

1111 = F    1111 = F  →  结果:0xFF

在编程中,0x 前缀表示十六进制(如 0xFF),0b 前缀表示二进制(如 0b11111111)。这些前缀告诉编译器:这不是十进制数。


交互演示:三栏同步转换器

下面这个转换器让你实时观察三种进制之间的对应关系。

在任意一栏输入数值,其余两栏会自动同步更新。

注意观察二进制栏下方的色块高亮——它展示了4 位一组对应 1 位十六进制的关系。

十进制 Decimal

基数=10, 数字=0~9

二进制 Binary

基数=2, 数字=0,1

十六进制 Hex

基数=16, 数字=0~F

试试看:在十进制栏输入 255,观察二进制栏的全 1 和十六进制栏的 FF。

这就是「一个字节的最大值」——理解了这个,很多概念就通了。


代码演示:完整的进制转换

实例

# 完整的进制转换工具(runoob 演示)

def decimal_to_binary(n):
    """十进制转二进制:除2取余法,展示完整步骤"""
    if n == 0:
        return "0"
    steps = []
    original = n
    while n > 0:
        remainder = n % 2
        quotient = n // 2
        steps.append((n, quotient, remainder))
        n = quotient

    result = ''.join(str(r) for _, _, r in reversed(steps))
    print(f"{original} 转为二进制:")
    for val, quot, rem in steps:
        print(f"  {val:3d} ÷ 2 = {quot:3d} 余 {rem}")
    print(f"  → 结果: {result}")
    return result

def binary_to_decimal(bin_str):
    """二进制转十进制:按权展开法"""
    decimal = 0
    length = len(bin_str)
    print(f"二进制 {bin_str} 按权展开:")
    for i, ch in enumerate(bin_str):
        power = length - 1 - i
        if ch == '1':
            value = 2 ** power
            decimal += value
            print(f"  位{power}: 1 x 2^{power} = {value}")
    print(f"  → 总和: {decimal}")
    return decimal

def bin_to_hex(bin_str):
    """二进制转十六进制:每4位一组查表"""
    while len(bin_str) % 4 != 0:
        bin_str = '0' + bin_str
    hex_map = {
        '0000':'0','0001':'1','0010':'2','0011':'3',
        '0100':'4','0101':'5','0110':'6','0111':'7',
        '1000':'8','1001':'9','1010':'A','1011':'B',
        '1100':'C','1101':'D','1110':'E','1111':'F'
    }
    result = ''
    groups = []
    for i in range(0, len(bin_str), 4):
        group = bin_str[i:i+4]
        hex_char = hex_map[group]
        groups.append(f"{group} → {hex_char}")
        result += hex_char
    print(f"二进制 {bin_str} 转十六进制:")
    for g in groups:
        print(f"  {g}")
    print(f"  → 0x{result}")
    return result

def hex_to_bin(hex_str):
    """十六进制转二进制:每位展开为4位"""
    rev_map = {
        '0':'0000','1':'0001','2':'0010','3':'0011',
        '4':'0100','5':'0101','6':'0110','7':'0111',
        '8':'1000','9':'1001','A':'1010','B':'1011',
        'C':'1100','D':'1101','E':'1110','F':'1111'
    }
    hex_str = hex_str.upper()
    result = ''
    for ch in hex_str:
        expanded = rev_map[ch]
        result += expanded
        print(f"  {ch} → {expanded}")
    # 去掉前导零(但至少保留一位)
    result = result.lstrip('0') or '0'
    print(f"  → {result}")
    return result

# 综合测试:以 RUNOOB 字符 'R' 的 ASCII 码 82 为中心
print("=" * 50)
print("测试值: 82 (ASCII 'R' from RUNOOB)")
print("=" * 50)
bin_result = decimal_to_binary(82)
print(f"82 → 二进制: {bin_result}\n")

dec_result = binary_to_decimal(bin_result)
print()

hex_result = bin_to_hex(bin_result)
print()

print("反向验证:十六进制 → 二进制")
hex_to_bin(hex_result)

print("\n" + "=" * 50)
print("测试值: 255 (一个字节的最大值)")
print("=" * 50)
bin_255 = decimal_to_binary(255)
print(f"二进制: {bin_255}")
hex_255 = bin_to_hex(bin_255)
print(f"十六进制: 0x{hex_255}")
print("注意:255 的二进制是8位全1,十六进制只用了2位 FF")

进阶:十六进制到十进制的快速转换

你已经会了两种转十进制的方法:一是按权展开(每个十六进制位 x 16 的幂),二是先转二进制再转十进制。

但还有一种更实用的方法——以二进制为「中间语言」

任何进制转换都可以通过二进制作为桥梁:

十进制 ←→ 二进制 ←→ 十六进制

因为十进制和十六进制之间的直接转换计算量较大,但各自与二进制的转换都非常简单。

十进制转二进制:除 2 取余。

十六进制转二进制:查表展开(每 1 位变 4 位)。