教科书把进位和借位讲成两个东西,但在二进制里它们是同一个操作在加法与减法下的两种表现。理解这一点,立刻能解释几个让初学者困惑的现象:为什么模 的加法只需要一个加法器(丢掉进位即可,完全精确);为什么模任意 的加法必须额外做一次比较与条件减法;以及为什么”模加法”在 Shor 类线路里才是真正的成本所在,而不是加法本身。

进位的布尔结构

第 位的全加器输出:

其中 是传入的进位, 是进位入。关键在于 maj(多数)是 、、 的多数票,而 。在可逆线路里,maj 要用 2 个 CNOT + 1 个 Toffoli 拼出来——这就是进位链里唯一昂贵的东西。

abcincout cout = majs = a ⊕ b
单比特全加器:多数门把进位传出,和位由异或给出

这张图是全站最值得逐列读一遍的线路:

  • 前两列把 cin 异或进 a 和 b,此时两线存的分别是 与 ;
  • 第 3 列一个 Toffoli:,再异或进 cin 就抵消掉末尾的 ,剩下 —— 正是多数。这也是整条进位链上唯一的 Toffoli;
  • 后两列用 cout 把 a、b 各自异或一次,抵消掉开头的 ,两线复原为原始 、;
  • 最后一列 就是和位。

注意 cout 上那个 Toffoli:它是整条进位链的瓶颈。这也是为什么加法器的改进几乎全集中在”如何更便宜地实现这一段”——相对相位门、结构重排、分带近似,见CDKM 加法器与门代价模型。

借位就是进位

考虑二进制减法 。若把 按位取反加 1(),则

也就是说,减法被化成了两次操作:逐位取反(全是 NOT 门,便宜),然后加常数 1(只有最低位需要特殊处理,进位从此处开始)。这也是 negadd 名字的由来(negate and add,见negadd 与减法)。

进一步的观察:在 比特字长下, 与 逐位相同,因为丢弃的正是那一位借位出。所以模减法与模加法是同一个问题。

符号扩展(sign extension)也是同一族操作:把 的符号位 复制到所有更高位。复制 1 就是取反,复制 0 就是保持——这正是”加法器 + 一个全 1 常量”的效果。换句话说,符号扩展、加 1、减常数,都是同一个进位链在不同入口条件下的实例。

为什么模 加法是免费的

回看上面的全加器:它输出 与 。如果我们只要 而丢弃 ,那就得到了 ,且完全精确、无需任何额外操作。

这是量子算术里一个少见的”免费午餐”。它也是所有”模 加法器”论文的立足点。

对比一下模任意 的情况:

要得到模 的结果,必须:

  1. 先算 ( 位,可能溢出);
  2. 判断 ;
  3. 若 ,则减去 (对选定的奇数模,只需减一次)。

第 2 步是比较,第 3 步是条件减法。两者都需要辅助比特与额外线路——这就是模加法在 Shor 类算法里成本高的真正原因。

比较器:被低估的那一步

模归约的瓶颈常常不是减法,而是比较 。实现上通常有两种:

  • 借位链法:算 ,看借位出。 当且仅当无借位出。
  • 前导零检测法:把 写成一个”掩码”,比较等价于检测差值的前导零个数,因此前导零检测器是模归约线路的核心子模块。

两种做法都需要 量级的辅助比特来承载中间差值,这也是各方案在”比特数 vs 深度”上分歧的根源。

取模与幂等:为什么只减一次

上面的第 3 步为什么减一次就够了?因为 ,所以 。因此

一次条件减法即达幂等。这也解释了为什么 Shor 里模 乘法的归约这一步”看起来简单”——它的简单性完全来自 为奇数这一前提。

三种加法的成本对照

运算是否需要比较辅助比特精确性
(第 位进位)否1(就地)精确
否1(就地)精确,免费丢弃进位
( 奇数)是精确
(归约)是精确

这张表是理解全站成本结构的骨架:线性算术已经是位最优,它的成本全在辅助比特上;模算术的成本全在比较器上。

延伸阅读