小柘小筑站

二进制编码

2025/11/05
3
0

一、基础:位(bit)与字节(Byte)的诞生——解决“信息怎么存”

在编码发展前,首先要确定“最小的信息单位”和“实用的存储单位”,这就是位和字节的由来。

1. 位(bit):计算机的“最小信息原子”

  • 诞生背景:计算机的核心是电子元件(如晶体管),只能有“通电(1)”和“断电(0)”两种状态,这就决定了计算机只能直接处理二进制数。

  • 定义:1个“位”就是1个二进制数位,只能表示 0 或 1,是计算机能处理的最小信息单位(比如“灯亮=1,灯灭=0”)。

  • 局限:1位只能表示2种状态,能承载的信息太少(比如无法表示一个数字或字母),必须组合使用。

2. 字节(Byte):“实用的信息基本单位”

  • 诞生背景:早期计算机需要统一“存储一个字符(如字母A、数字5)”的最小空间,避免不同设备存储规则混乱。

  • 定义:1个“字节”固定等于 8个连续的位(8bit),1字节能表示的状态数是 2^8 = 256 种(从 00000000 到 11111111),刚好能覆盖当时需要的所有字符(字母、数字、符号)。

  • 发展:字节成为计算机存储的“基本单位”,后续的KB(1KB=1024Byte)、MB(1MB=1024KB)、GB等,都是基于字节的倍数扩展,直到现在仍是计算机存储的核心单位(比如文件大小、内存容量都以字节为基础)。

二、编码的发展:从“英文够用”到“全球通用”——解决“信息怎么表达”

有了字节(8bit=256种状态)这个基础,编码的作用就是“给每个状态分配具体的含义(比如哪个二进制对应字母A,哪个对应汉字‘中’)”,发展过程分三个关键阶段:

1. 第一阶段:ASCII 码(1963年)——解决英文和基础符号的表达

  • 背景:早期计算机主要用于英语环境,需要给英文26个字母(大小写)、10个数字、标点符号(如!、,)分配二进制编码。

  • 规则:用1个字节(8bit)的 低7位 表示(高1位固定为0),共 2^7=128 种编码,完全覆盖英文场景:

  • 比如字母“A”对应二进制 01000001(十进制65),“a”对应 01100001(十进制97);

  • 数字“0”对应 00110000(十进制48),符号“!”对应 00100001(十进制33)。

  • 局限:只能处理英文,无法表示中文、日文、俄文等其他语言(这些语言的字符远超128个)。

2. 第二阶段:扩展编码与本地化编码(1980s-1990s)——各国自主解决“本国语言”问题

  • 背景:计算机普及到非英语国家,需要表示本国文字(如中文有几万个汉字),但ASCII码只用了1字节的7位,于是各国开始利用“高1位”扩展。

  • 常见编码

  • 中国GB2312(1980年):用1个字节表示ASCII字符,用 2个字节 表示中文汉字,共收录6763个常用汉字(比如“中”对应二进制 11010110 11000001);

  • 中国GBK(1995年):在GB2312基础上扩展,收录21003个汉字,还支持繁体字、日文假名等;

  • 日本Shift_JIS:支持日文汉字和假名;

  • 欧洲ISO-8859-1:支持法语、德语等欧洲语言的特殊字符(如é、ü)。

  • 局限编码不兼容——比如用GB2312编码的“中”字,用Shift_JIS打开会显示乱码,无法实现“全球文件通用”(比如一封中文邮件发给日本用户,对方打开是乱码)。

3. 第三阶段:Unicode 与 UTF-8(1990s至今)——实现“全球字符统一编码”

  • 背景:为解决“编码混乱”问题,国际组织(Unicode Consortium)推出“Unicode标准”,目标是给全球所有语言的字符(包括汉字、日文、 emoji 等)分配唯一的“编号(码点)”,再通过“传输编码(如UTF-8)”把编号转换成二进制存储。

  • 核心逻辑:分两步实现“统一表达”:

  1. Unicode 码点:给每个字符分配唯一的十进制编号(比如“中”的码点是 U+4E2D,十进制是 20013;“A”的码点是 U+0041,和ASCII码一致);

  2. UTF-8 传输编码:把 Unicode 码点转换成二进制存储,特点是“变长字节”——根据码点大小用1~4个字节表示:

  • 英文/数字(码点小):用1个字节(和ASCII码完全兼容,解决“旧文件兼容”问题);

  • 中文/日文(码点中等):用3个字节(比如“中”的UTF-8二进制是 11100100 10111000 10101101);

  • 特殊字符(如 emoji):用4个字节(比如“😂”的码点是 U+1F602,UTF-8用4个字节表示)。

  • 优势

  • 全球兼容:任何语言的字符用UTF-8编码后,在全球任何设备打开都不会乱码;

  • 节省空间:英文仍用1字节,比固定2字节的编码(如UTF-16)更省存储(比如英文文档体积更小)。

  • 现状:UTF-8 已成为当前互联网、操作系统(Windows、macOS)、编程语言(Java、Python)的 默认编码,彻底解决了“全球字符统一存储”的问题。

三、总结:发展脉络的核心逻辑

整个发展过程围绕“从‘局部够用’到‘全球通用’”展开,每一步都在解决前一阶段的局限:

  1. 位与字节:确定“最小存储单位”,为编码提供“硬件基础”;

  2. ASCII 码:解决“英文场景”的基本表达,但局限于英语;

  3. 本地化编码(GB2312、Shift_JIS):解决“本国语言”表达,但导致编码混乱;

  4. Unicode + UTF-8:通过“统一码点+变长编码”,实现“全球字符兼容”,成为当前标准。

简单说:从“只能存A和1”到“能存中文、emoji且全球不乱码”,本质是“编码规则从局部到全局、从单一到统一”的进化。

要不要我帮你整理一份 “编码发展关键节点对比表”?把每个阶段的时间、核心目标、代表编码、优缺点都列出来,方便你快速回顾核心信息。

单精度

第一步:确定符号位

  • 因为是负数,符号位 = 1


第二步:将绝对值转换为二进制

先处理 9.625 的二进制表示:

  • 整数部分:9 →

  • 小数部分:0.625 →

  • 0.625 × 2 = 1.25 → 取1

  • 0.25 × 2 = 0.5 → 取0

  • 0.5 × 2 = 1.0 → 取1
    所以 0.625 = 0.101₂

  • 合并:9.625 = 1001.101₂


第三步:规格化(科学计数法)

将二进制数写成 1.xxxx × 2^e 的形式:

  • 1001.101 = 1.001101 × 2³

所以:

  • 尾数(mantissa) = 001101...(后面补0到23位)

  • 指数 e = 3


第四步:计算带偏置的指数(Exponent)

单精度偏置 = 127
所以存储的指数 = 3 + 127 = 130

130 的二进制是:

  • 130 = 128 + 2 → 10000010₂


第五步:组合三部分

  • 符号位(1位)1

  • 指数(8位)10000010

  • 尾数(23位):取小数点后的部分 001101,后面补0到23位
    00110100000000000000000


最终结果(32位):

1 10000010 00110100000000000000000

按字节分组(每8位)更清晰:

11000001 00011010 00000000 00000000

十六进制表示为:

  • 0xC11A0000


验证(可选)

你可以用编程语言验证,例如在 Python 中:

import struct
bits = struct.unpack('>I', struct.pack('>f', -9.625))[0]
print(hex(bits))  # 输出: 0xc11a0000

图示(文字版)

 31   30      23 22                                    0
+----+--------+----------------------------------------+
| 1  |10000010|00110100000000000000000                 |
+----+--------+----------------------------------------+
 S    Exponent           Fraction (Mantissa)
  • S = 1 → 负数

  • Exponent = 130 → 实际指数 = 130 − 127 = 3

  • Mantissa = 1.001101₂ → 实际数值 = −1.001101₂ × 2³ = −9.625


希望这个例子能帮你更清楚理解 IEEE 754 单精度浮点数的结构!如果你还想看其他例子(比如 0、无穷大、NaN、很小的数等),也可以告诉我。

双精度

双精度浮点数的基本结构(64位)

部分

位数

说明

符号位(Sign)

1 位

0 表示正数,1 表示负数

指数(Exponent)

11 位

偏置值(bias)为 1023

尾数/小数部分(Fraction / Mantissa)

52 位

隐含前导 1(即实际尾数为 1.f)

总长度:1 + 11 + 52 = 64 位


文字图示

63   62                52 51                                               0
+----+------------------+--------------------------------------------------+
| S  | Exponent (11位)   | Fraction / Mantissa (52位)                       |
+----+------------------+--------------------------------------------------+
  • S:符号位(第63位)

  • Exponent:第62位到第52位(共11位)

  • Fraction:第51位到第0位(共52位)


举个例子:用双精度表示 -9.625

这个数我们之前用单精度表示过,现在用双精度,过程类似,但精度更高、指数范围更大。

第一步:符号位

  • 负数 → S = 1

第二步:二进制表示

  • 9.625 = 1001.101₂ = 1.001101₂ × 2³

第三步:指数(带偏置)

  • 实际指数 e = 3

  • 双精度偏置 = 1023

  • 存储指数 = 3 + 1023 = 1026

1026 的二进制(11位):

  • 1026 = 1024 + 2 → 10000000010₂

第四步:尾数(52位)

  • 小数部分是 .001101

  • 补0到52位:

0011010000000000000000000000000000000000000000000000

第五步:组合

1 10000000010 0011010000000000000000000000000000000000000000000000

按8位分组(64位 = 8字节):

11000000 00100011 01000000 00000000 00000000 00000000 00000000 00000000

十六进制表示:

  • 0xC023400000000000

✅ 验证(Python):

import struct
bits = struct.unpack('>Q', struct.pack('>d', -9.625))[0]
print(hex(bits))  # 输出: 0xc023400000000000

单精度 vs 双精度 对比

特性

单精度(float32)

双精度(float64)

总位数

32 位

64 位

符号位

1 位

1 位

指数位

8 位(bias=127)

11 位(bias=1023)

尾数位

23 位

52 位

有效精度

≈7 位十进制数字

≈15–17 位十进制数字

指数范围

≈ ±10³⁸

≈ ±10³⁰⁸


特殊值(双精度也支持)

  • :指数全0,尾数全0(有 +0 和 -0)

  • 无穷大(∞):指数全1,尾数全0

  • NaN(非数):指数全1,尾数非0

  • 非规格化数(Denormal):指数全0,尾数非0(用于表示非常接近0的数)


资源下载

提示:如遇链接失效,请在评论区留言反馈