形式陈述
“只做了十次乘法”还不能说明一个算法很快:被乘的数可能每次都长一倍。位复杂度 把时间复杂度 公理库 时间复杂度 Time complexity · Running time 在固定计算模型与输入编码后,算法运行步骤数随输入规模增长的量级。 的单步成本落实到有限个 bit 的读写、布尔运算以及指定模型的存储访问上。必须同时固定输入编码与计算模型;一个严格实现是使用固定有限字母表、固定条数工作带的图灵机 公理库 图灵机 Turing machine 通过有限控制、可读写纸带和移动读写头刻画一般算法计算能力的模型。 ,按局部转移计步。带头移动也收费,不能把任意位置的取位操作暗中视为免费。
本页以无前导零的二进制表示非负整数,并约定零写成一个 bit。整数 a 的位长为
ℓ ( a ) = { 1 , a = 0 , ⌊ log 2 a ⌋ + 1 , a > 0. 元组另需可解析的分隔或长度信息。输入规模 n 是完整编码的总长度,而不是其中某个整数的数值。对固定算法 A ,记 B A ( x ) 为这套模型下处理输入 x 的总位成本,最坏位复杂度为 B A ( n ) = max | x | = n B A ( x ) ;合法编码、非法输入与停机约定应和时间复杂度定义保持一致。
若算法的第 i 次算术操作处理位长为 b i , 1 , … , b i , r i 的数,采用的实现成本为 C i ,分析应累加
∑ i = 1 q C i ( b i , 1 , … , b i , r i ) , 再加上尚未包含在这些子程序中的控制、访存与输入输出成本。这里 q 是算术操作次数;它只是计费项数,不是总账单。即使所有操作都叫“乘法”,各项也可能因为中间数增长而相差很大。
直觉
二进制长度把“数字有多大”转换成“必须保存多少信息”。2 1000 的数值巨大,但写下它只需 1001 bit;反过来,输入一个长度约为 1000 bit 的指数 e ,要求完整输出 3 e ,答案可能需要指数多的位。
位复杂度也不等于实际处理器逐个 bit 地执行。Word-RAM 模型 公理库 Word-RAM 模型 Word RAM · Word-RAM model 以 w 位机器字、常数时间随机访存和明确字级操作集分析算法的随机访问机模型。 允许一个有限宽度的机器字作为计费单位,实际大整数库则常按字分块。两种分析都可以有用,但从字操作数换成位成本,必须展开操作和存储实现,尤其不能把任意长整数视为一个字。
例子与边界
同样是算术操作,单次成本不同
对至多 b bit 的两个非负整数,传统进位加法扫描各位,耗时 O ( b ) ,输出至多 b + 1 bit。传统乘法形成至多 b 行移位部分积,每行至多 2 b bit,总成本为 O ( b 2 ) 。这两个界对应具体逐位实现;乘法的二次界是该算法的上界,不是所有乘法算法的下界。
输入输出本身也有成本。在每步只能写常数个输出符号的模型中,显式输出 L bit 至少需要 Ω ( L ) 步。若任务要求完整读入 n bit,读取需 Ω ( n ) ;若正确性迫使某些最坏输入上的全部位都被检查,也有相同下界。但不能据此断言所有任务都必须读完整个输入,例如只返回第一个 bit 的任务可忽略后缀。
重复平方:少量乘法怎样生成很长的答案
固定底数 3 ,令 x 0 = 3 、x i + 1 = x i 2 ,于是 x i = 3 2 i 。四次平方得到:
i
完整整数 x i
ℓ ( x i )
r i = x i mod 17
ℓ ( r i )
0
3
2
3
2
1
9
4
9
4
2
81
7
13
4
3
6561
13
16
5
4
43046721
26
1
1
例如 2 6 ≤ 81 < 2 7 ,所以 81 占 7 bit;2 25 ≤ 43046721 < 2 26 ,所以最后一项占 26 bit。位长来自二进制表示,不能用表中的十进制数字大小直接代替。
图片加载失败 重复平方的两条位长轨迹 一般地,ℓ ( x i ) = ⌊ 2 i log 2 3 ⌋ + 1 = Θ ( 2 i ) 。因此用传统乘法算到 x k ,平方部分的成本是
∑ i = 0 k − 1 O ( ℓ ( x i ) 2 ) = ∑ i = 0 k − 1 O ( 4 i ) = O ( 4 k ) . 这个推导没有把 k 次平方一律按初始的两位整数收费。即使换用更快的乘法,完整输出仍有 Ω ( 2 k ) 的成本:当指数 e = 2 k 用二进制给出时,指数输入仅有 k + 1 bit,而 3 e 的输出有 Θ ( 2 k ) bit。因此“重复平方用了 O ( log e ) 次乘法”并不能推出完整求幂对输入位长是多项式时间。
每步取模为什么改变结论
若任务改为求 3 2 k mod 17 ,可以令 r 0 = 3 、r i + 1 = r i 2 mod 17 。关键是每次平方之后立即取模 ,而不是先生成完整整数再取模。表中 9 2 mod 17 = 13 、13 2 mod 17 = 16 、16 2 mod 17 = 1 ,每次存回的结果始终小于 17 。
推广到 m bit 的模数 N ≥ 2 ,已约化的余数至多 m bit;一次平方先产生至多 2 m bit 的积,再用传统长除法求余,二者合计 O ( m 2 ) 位操作。对 e = 2 k 只需 k 次这样的模平方,算术部分为 O ( k m 2 ) ;把读入与初始处理包含在内可写为 O ( ( k + 1 ) m 2 ) 。任意 k bit 指数可沿二进制位做平方及必要的模乘,也得到 O ( k m 2 ) 的算术成本。这里默认底数已约化或本身至多 m bit;若底数更长,其读取与首次求余必须另计。
推论与应用
分析大整数、精确有理数和符号表达式算法时,应先控制中间表示的长度,再统计操作次数。分数约分可能压低后续成本,延迟约分则可能造成分子、分母膨胀;只比较加乘次数无法决定哪种实现更快。浮点运算若固定精度,可以采用另一套固定字长成本,但不能据此声称任意精度精确运算也是常数时间。
位复杂度还帮助检查确定性时间类 公理库 确定性时间复杂性类 Deterministic time class · DTIME 由确定性图灵机在给定时间界内判定的语言集合。 中的“多项式”究竟相对于什么参数。按数值 N 执行 N 轮,与按 ℓ ( N ) 执行多项式轮数是两种保证;随后再使用渐近记号 公理库 渐近记号 Asymptotic notation · Big O notation 忽略常数和低阶项,比较函数在输入趋于无穷时的增长速度。 ,才能避免编码变化掩盖指数成本。
自测。 输入二进制指数 e = 2 k ,分别要求输出 2 e 的完整二进制串,以及输出 2 e mod 17 。前者的输出下界是多少?后者能否套用同一下界?检查标准:完整串是一个 1 后接 e 个 0,长度为 2 k + 1 ;模结果至多 5 bit,不受这个指数输出下界约束。若允许把答案写成字符串“2 e ”,那已经改变了输出表示与计算任务。
参考资料