把十分之一的比特翻掉
前十三章假设比特能完好送到。现实不是这样:线会串扰,无线会衰落,内存会被宇宙射线打中。卷 IV 的问题只有一个——在一条会说谎的线上,怎么说出不会错的话。
一条线路会随机翻掉一些比特。哪种情况下这条线最没用(每次使用能传的信息最少)?
最简单的噪声模型
把现实中所有的噪声源——热噪声、串扰、衰落、宇宙射线——统统抽象成一件事:
你发一个比特。它有 p 的概率被翻成相反的,有 1−p 的概率原样通过。每一位独立。
1−p
0 ─────────▶ 0
╲ p ╱
╲──────╱
╱──────╲
╱ p ╲
1 ─────────▶ 1
1−p
「对称」指的是 0 翻成 1 和 1 翻成 0 的概率一样。这个模型简单得离谱,但它抓住了本质,而且香农所有的核心结论都能在它身上讲清楚。
先看一眼它有多难受:
把 p 拖到 0.1,看那五个字母被打成了什么样。40 个比特里翻掉 4 个,「HELLO」就已经面目全非了。
那么这条线还能传多少
直觉可能会说:「翻掉 10%,那大概还剩 90% 吧。」
不对,而且差得挺远。正确答案是:
C = 1 − H(p) 【二元对称信道的容量】 p = 0.1 → C = 1 − 0.469 = 【0.531 比特 / 每次使用】
只剩 53%,不是 90%。为什么?
收方拿到一个比特。这个比特里包含两件事:
- 发方到底发的是 0 还是 1;
- 这一位到底翻没翻。
第二件事本身就是一个随机变量,它的熵是 H(p) = 0.469 比特。这部分不确定性占掉了收到的比特里的一份,而它对你毫无用处——它是关于噪声的信息,不是关于消息的信息。
于是留给消息的只剩 1 − H(p) = 0.531。
用互信息的语言写(第 19 章会正式定义):
C = max I(X; Y) = H(Y) − H(Y|X) = 1 − H(p) # H(Y) 收到的那一位有多少不确定性 最多 1 比特 # H(Y|X) 已知发的是什么,收到的还有多少不确定 = H(p),纯噪声 # 相减 = 收到的东西里,真正来自发送方的那部分
最坏的不是「全翻」
现在回到开头那个问题。把 demo 里的 p 一路拖到 1,看看容量:
p = 0.0 C = 1.000 # 完美信道 p = 0.1 C = 0.531 p = 0.2 C = 0.278 p = 0.3 C = 0.119 p = 0.5 C = 0.000 ← 【最坏】 p = 0.7 C = 0.119 p = 0.9 C = 0.531 p = 1.0 C = 1.000 ← 又满了!
「每一位都翻」是完全可预测的。收方把收到的全部取反,就得到了原文,一个错都没有。
坏的不是噪声大,是噪声不可预测。
而最不可预测的地方在正中间:p = 0.5。这时收到的比特和发出的比特统计独立——你收到一个 1,发的是 0 还是 1 的概率各半。这条线传的信息量是 0,你不如自己在家抛硬币。
这个观察在工程上有真实的用处:
- 差分信号(LVDS、USB、以太网、HDMI)。用两根线传一对反相的信号,接收端取差值。共模干扰同时打在两根线上,一相减就消掉了。这是「可预测的噪声不算噪声」的物理版。
- 回声消除。你的手机通话里,扬声器的声音会被自己的麦克风收进去。但那个声音是已知的(就是你刚播出去的),所以可以精确地减掉。
- DRAM 的行锤(Rowhammer)和纠错。某些位翻转有规律(同一行反复访问导致邻行翻位),一旦规律被识别,就能被针对性地防御。
- 反过来的用法:加密。好的密文必须让攻击者觉得每一位都是
p = 0.5——「和随机不可区分」就是「容量为 0」的另一种说法。密码学的很多安全定义,翻译过来就是「攻击者能获得的互信息可忽略」。
「知道哪里错了」这件事本身值很多比特,这是一个反复出现的主题:
擦除信道(知道哪位丢了) C = 1 − p p=0.1 → 0.900 二元对称信道(不知道哪位错) C = 1 − H(p) p=0.1 → 0.531 # 同样丢 10%,「知道丢在哪」比「不知道」多传 69% 的信息。
这就是为什么网络协议里校验和如此重要:它把「悄悄出错」(BSC,很难对付)变成「明确丢包」(擦除信道,好对付得多)。TCP 的重传机制建立在这个转换上。一个坏包被丢掉,比一个坏包被当成好包用,代价小得多。
容量的正式定义是 C = maxp(x) I(X;Y)——在所有可能的输入分布上取最大值。
为什么要取 max?因为容量是信道的性质,不该取决于你怎么用它。如果你只发 0 不发 1,那你一个比特都没传,但这是你的问题,不是信道的问题。所以容量定义为「最会用的人能达到的极限」。
对二元对称信道,最优输入分布恰好是均匀的(0 和 1 各一半)——这有直观理由:信道是对称的,所以没有理由偏爱任何一个输入符号。
这也给出一个实用推论:要跑满一条信道,你发出去的比特流必须看起来像随机的。而一段没压缩的文本远远不是随机的。所以「先压缩再传输」不只是省流量,它是跑满信道容量的前提。
这件事有个名字,叫信源–信道分离定理:先把信源压到熵(第 5–9 章),再对压完的比特做纠错编码(第 15–17 章),这两步分开做,和联合优化一样好。这条定理是现代通信系统架构分层的理论依据——它解释了为什么「压缩」和「纠错」在每一个系统里都是两个独立的模块。
(要补一句边界:分离定理在点对点、无限长码块的理想条件下成立。在多用户、有时延约束的现实场景里,联合设计有时确实更好。但作为工程架构的默认选择,分离几乎总是对的。)
如果你选了 D,那是最自然的直觉——「全错了当然最糟」。但全错是完全可预测的,取个反就完事了。
这一题真正想让你换掉的观念是:噪声的危害不在幅度,在不可预测性。一个稳定偏差 100 度的温度计,你减掉 100 就能用;一个随机偏差 ±1 度的温度计,你什么都做不了。
而 C = 1 − H(p) 这个式子里那个 H(p),量的正是「噪声本身有多难猜」。
这一章的一句话
一条会翻位的线,每次使用能可靠带走 1 − H(p) 比特。被吃掉的那部分不是「坏掉的数据」,是「这一位到底翻没翻」这个问题本身占掉的——所以最坏的信道不是全翻,是翻一半。
下一章:既然线会出错,那就多说几遍呗。这个直觉几乎每个人都有,而它在算术上非常昂贵。我们会算清它到底多贵——要把错误率压到十亿分之一,重复码需要重复 35 次,码率掉到 0.029。而香农说你本来可以跑 0.531。