fbpx
维基百科

平方求幂

数学程序设计中,平方求冪(英語:exponentiating by squaring)或快速冪是快速计算一个数(或更一般地说,一个半群的元素,如多項式方阵)的大正整数的一般方法。这些算法可以非常通用,例如用在模算數或矩阵幂。对于通常使用加性表示法的半群,如密码学中使用的椭圆曲线,这种方法也称为double-and-add

基本方法

该方法是基于观察到,对于正整数 ,可知

 

该方法使用指数的位(二进制的位,即bit,下文称为“位”)来确定计算哪些幂。

此例显示如何使用此方法计算  。 幂指数13的二进制为1101。这些位按照从左到右的顺序使用。 指数有4位,所以有4次迭代。

首先,将结果初始化为1: 

  1.  ,第1位 = 1,所以计算  
  2.  ,第2位 = 1,所以计算  
  3.  ,第3位 = 0,所以这一步什么都不做。
  4.  ,第4位 = 1,所以计算  

这可以按照下面的递归算法来实现:

 Function exp_by_squaring(x, n) if n < 0 then return exp_by_squaring(1 / x, -n); else if n = 0 then return 1; else if n = 1 then return x ; else if n is even then return exp_by_squaring(x * x, n / 2); else if n is odd then return x * exp_by_squaring(x * x, (n - 1) / 2); 

尽管不是尾调用,但是通过引入辅助函数,该算法可以被重写成尾递归算法:

 Function exp_by_squaring(x, n) exp_by_squaring2(1, x, n) Function exp_by_squaring2(y, x, n) if n < 0 then return exp_by_squaring2(y, 1 / x, - n); else if n = 0 then return y; else if n = 1 then return x * y; else if n is even then return exp_by_squaring2(y, x * x, n / 2); else if n is odd then return exp_by_squaring2(x * y, x * x, (n - 1) / 2). 

该算法的迭代版本的辅助空间是有界的,代码如下

 Function exp_by_squaring_iterative(x, n) if n < 0 then x := 1 / x; n := -n; if n = 0 then return 1 y := 1; while n > 1 do if n is even then x := x * x; n := n / 2; else y := x * y; x := x * x; n := (n  1) / 2; return x * y 

c++实现(非递归) 返回  求模

long long power(long long p, long long n) {  long long ans = 1;  while (n)  {  if (n & 1) ans = (ans * p) % Mod;  p = p * p % Mod;  n >>= 1;  }  return ans; } 

计算复杂度

简要分析表明此算法用了   次平方,以及至多   次乘法,其中   表示向下取整函数。更确切地说,做乘法的次数比 n二进制展开的次数要少一次。对于 n 大于4左右的时候,这种算法在计算上就已经比天真地将它与自身重复地相乘更高效了。

每次平方的结果大约是前一次结果的两倍,因此,如果两个 d 位数的相乘的实现要进行 O(dk) 次计算(其中 k 为一固定值),那么计算 xn 的复杂度为:

 

2k

此算法先把指数展开成 2k 形式,然后再计算 xn 的值。它在1939年由Brauer首次提出。在下面的算法中,使用以下函数 f(0) = (k,0) 和 f(m) = (s,u),其中 m = u·2su 为奇数。

算法:

输入
G 的一个元素 x,参数 k > 0,一个非零整数 n = (nl−1, nl−2, ..., n0)2k 以及预计算的值  
输出
G 中的元素 xn
y := 1; i := l-1 while i>=0 do (s,u) := f(ni) for j:=1 to k-s do y := y2 y := y*xu for j:=1 to s do y := y2 i := i-1 return y 

为了获得最佳效率,k 应该是满足

 

的最小整数。[1]

滑动窗口法

此方法是 2k 法的更高效的变体。例如,要计算398次幂,二进制展开为 (110 001 110)2,采用长度为3的窗,使用 2k 法,需要计算 1, x3, x6, x12, x24, x48, x49, x98, x99, x198, x199, x398。 但也可以计算 1, x3, x6, x12, x24, x48, x96, x192, x198, x199, x398,这就会省下一次乘法,相当于是计算 (110 001 110)n2 的值

以下是一般算法:

算法:

输入
G的元素 x,非负整数 n=(nl-1,nl-2,...,n0)2,一个参数 k>0,以及预计算的值  
输出
元素 xnG

算法:

y := 1; i := l-1 while i > -1 do if ni=0 then y:=y2' i:=i-1 else s:=max{i-k+1,0} while ns=0 do s:=s+1 [notes 1] for h:=1 to i-s+1 do y:=y2 u:=(ni,ni-1,....,ns)2 y:=y*xu i:=s-1 return y 

蒙哥马利阶梯法

求幂的许多算法都不提供对旁路攻击的防护。也就是说,监测到乘方运算的攻击者可以(部分)还原所计算的指数。就如众多公钥加密系统中那样,如果指数需要保密的话,这就是个问题了。一个叫做蒙哥马利阶梯[2]的方法解决了这个问题。

给定一个非零正整数的二进制展开 n=(nk-1...n0)2(其中 nk-1=1),可以以下面方式计算 xn

x1=x; x2=x2 for i=k-2 to 0 do If ni=0 then x2=x1*x2; x1=x12 else x1=x1*x2; x2=x22 return x1

该算法会执行一系列固定的操作(复杂度log n):无论每一位的具体值如何,指数中的每一位都会进行乘法和平方。

蒙哥马利阶梯法的这种具体实现还无法抵御缓存时序攻击英语timing attack:当根据秘密指数的位值访问不同的变量时,内存访问延迟仍可能被攻击者观察到。

固定基底的幂

当基底固定而指数变化时,可以使用几种方法来计算 xn。可以看出,预计算在这些算法中起着关键作用。

姚期智的方法

姚期智的方法与 2k 法不同,是把指数以 b=2k 为基底展开,并按上面的算法进行计算。令 n, ni, b, bi 为整数。

把指数 n 写成

  其中对所有   都有  

xi = xbi。该算法使用等式

 

给定 G 的元素 x,指数 n 写成上述形式,并且预先计算 xb0....xbw-1 的值,元素 xn 就可以用下面的算法计算了。

 y=1,u=1 and j=h-1 while j > 0 do for i=0 to w-1 do if ni=j then u=u*xbi y=y*u j=j-1 return y 

如果令 h=2kbi = hi,那么这些 ni 就是 nh 为基的每一位。姚期智的方法是把之前的那些 xi 收集到 u 中,which appear to the highest power  ;in the next round those with power   are collected in u as well etc. 变量 y 被原始的 u 乘了   次,内第二高的指数乘了   次…… 该算法计算 xn 要用   次乘法,存储   个元素。[1]

欧几里得法

欧几里德法首先在P.D Rooij的《使用预计算和向量加法链的高效求幂》(Efficient exponentiation using precomputation and vector addition chains)中介绍。

这种计算群 G n 为自然数)的方法是,递归地使用下面的等式:

 , where  
(换句话说,用指数 n1n0 的欧几里得除法来返回商 q 和余数 n1 mod n0)。

给定群 G 中的基底元素 x,把指数   用姚期智的方法写出来,然后就可以用预计算的   个值   计算   了。

 Begin loop Find  , such that  ; Find  , such that  ; Break loop if  ; Let  , and then let  ; Compute recursively  , and then let  ; End loop; Return  . 

该算法首先在 ni 中找到最大值,在找到集合 { ni \ iM } 中的最大值。 然后递归求 xMq 次幂,把这个值乘以 xN,赋值给 xN;把 nMnN 的结果赋值给 nM

更多应用

这一思路还可用于计算大指数幂除以一个数的余数。特别是在密码学中,在整数除以q的余数中计算幂是很有用处的。在中计算整数幂也是很有用的,使用法则

Power(x, −n) = (Power(x, n))−1.

该方法对所有半群都适用,通常用于计算矩阵的幂。

例如,如果使用朴素的方法,计算

13789722341 (mod 2345)

将花费很长时间以及大量的存储空间:计算 13789722341,并除以2345求。即便使用更有效的方法也需要很长时间:求13789的平方,除以2345求余,将结果乘以13789,再求余,一直往下计算。这会需要   次模乘。

把“*”理解为 x*y = xy mod 2345(即相乘后取模)后,应用上面的平方求幂算法,只需要27次乘法和整数除法(所有这些都可以存储在单个机器字中)就可以完成计算了。

示例实现

通过2的幂进行计算

这是用Ruby写的上述算法的非递归实现。

由于低级语言会将 n=n/2 隐式向0取整,n=n-1 对那些语言来说,就是冗余的步骤了。 n[0]是n的二进制表示的最右边的位,所以如果它是1,则该数是奇数,如果它是零,则该数是偶数。它也是以2为模n的余数。

def power(x,n) result = 1 while n.nonzero? if n[0].nonzero? result *= x n -= 1 end x *= x n /= 2 end return result end 

运行实例:计算 310

parameter x = 3 parameter n = 10 result := 1 Iteration 1 n = 10 -> n is even x := x2 = 32 = 9 n := n / 2 = 5 Iteration 2 n = 5 -> n is odd -> result := result * x = 1 * x = 1 * 32 = 9 n := n - 1 = 4 x := x2 = 92 = 34 = 81 n := n / 2 = 2 Iteration 3 n = 2 -> n is even x := x2 = 812 = 38 = 6561 n := n / 2 = 1 Iteration 4 n = 1 -> n is odd -> result := result * x = 32 * 38 = 310 = 9 * 6561 = 59049 n := n - 1 = 0 return result 

运行实例:计算 310

result := 3 bin := "1010" Iteration for digit 2: result := result2 = 32 = 9 1010bin - Digit equals "0" Iteration for digit 3: result := result2 = (32)2 = 34 = 81 1010bin - Digit equals "1" --> result := result*3 = (32)2*3 = 35 = 243 Iteration for digit 4: result := result2 = ((32)2*3)2 = 310 = 59049 1010bin - Digit equals "0" return result 

JavaScript-Demonstration: http://home.mnet-online.de/wzwz.de/temp/ebs/en.htm (页面存档备份,存于互联网档案馆

幂的乘积的计算

平方求幂也可用于计算2个或多个幂的乘积。 如果基础群或半群是可交换的,那么常常可以通过同时计算乘积来减少乘法的次数。

例子

式子 a7×b5 可以分三步计算:

((a)2×a)2×a (计算 a7 需要四次乘法)
((b)2)2×b   (计算 b5 需要三次乘法)
(a7)×(b5) (计算二者乘积需要一次乘法)

所以总共需要八次乘法。

更快的解法是同时计算这两个幂

((a×b)2×a)2×a×b

总共只需要6次乘法。注意 a×b 计算了两次;结果可以在第一次计算后存储,这将乘法计数减少到5次。

有数字的例子:

27×35 = ((2×3)2×2)2×2×3 = (62×2)2×6 = 722×6 = 31,104

如果至少有两个指数大于1的话,同时计算幂就会比单独计算减少乘法次数。

使用变换

如果表达式在计算前进行变换,上面的例子 a7×b5 也可以只用5次乘法就计算出来:

a7×b5 = a2×(ab)5 其中 ab := a×b

ab := a×b(一次乘法)
a2×(ab)5 = ((ab)2×a)2×ab(四次乘法)

这个变换可以推广成下面的方案:
对于计算 aA×bB×...×mM×nN
首先:定义 ab := a×b, abc = ab×c, ...
然后:计算变换后的表达式 aA−B×abB−C×...×abc..mM−N×abc..mnN

在计算之前进行变换通常会减少乘法计数,但在某些情况下也会增加计数(请参见下面最后一个示例),因此在使用变换后的表达式进行计算之前,最好检查一下乘法的次数。

例子

对于下面的表达式,表中显示了分开计算每个幂,在不进行变换的情况下同时进行计算,以及在变换后同时进行计算的乘法次数。

例子 a7×b5×c3 a5×b5×c3 a7×b4×c1
分开计算 [((a)2×a)2×a] × [((b)2)2×b] × [(c)2×c]
11次乘法)
[((a)2)2×a] × [((b)2)2×b] × [(c)2×c]
10次乘法)
[((a)2×a)2×a] × [((b)2)2] × [c]
8次乘法)
同时计算 ((a×b)2×a×c)2×a×b×c
8次乘法)
((a×b)2×c)2×a×b×c
7次乘法)
((a×b)2×a)2×a×c
6次乘法)
变换 a := 2   ab := a×b   abc := ab×c
(2次乘法)
a := 2   ab := a×b   abc := ab×c
(2次乘法)
a := 2   ab := a×b   abc := ab×c
(2次乘法)
之后的计算 (a×ab×abc)2×abc
(4次乘法 ⇒ 总共6次)
(ab×abc)2×abc
(3次乘法 ⇒ 总共5次)
(a×ab)2×a×ab×abc
(5次乘法 ⇒ 总共7次)

用有符号数字重新编码

在某些计算中,如果允许负系数(也就会需要用基底的倒数)的话,只要在 G 中计算倒数很快或者已经预先计算,求幂会更加高效。例如,当计算 x2k−1 时,二进制方法需要 k−1 次乘法和 k−1 次平方。不过可以用 k 次平方得到 x2k,然后乘以 x−1 得到 x2k−1

为此,定义以 b 为基数的整数 n有符号数字表示英语signed-digit representation

 

有符号二进制表示也就是选取 b=2  的表示法。记为  。有多种计算这种表示的方法。该表示不是唯一的,例如,取 n=478   给出了两个不同的有符号二进制表示,其中   表示 -1。由于在二进制方法中,n 的基2表示的每个非零项都要计算乘法,因此感兴趣的是找到非零项数量最少的有符号二进制表示,即具有最小汉明重量的表示。有一种方法是计算非相邻形式英语non-adjacent form(简称NAF)的有符号二进制表示,它满足对所有   ,记为  。例如,478的NAF表示为  。这种表示总是有最小的汉明重量。下面的简单算法可以计算   的整数   的NAF表示:

  for i = 0 to l - 1 do     return   

Koyama和Tsuruoka的另一种算法并不要求   这样的条件;它仍然可以让汉明重量最小化。

替代方法及推广

平方求幂可以看作是一个次优的加法链求幂英语addition-chain exponentiation算法:它通过由重复指数加倍(平方)和指数递增(乘以 x)组成的加法链英语addition chain来计算指数。更一般地,如果允许任何先前计算的指数相加(通过乘以 x 的幂),有时可以让求幂运算的乘法次数更少(但通常使用更多的内存)。n=15 时的最少次数:

  (平方求幂,6次乘法)
  (最优加法链,在复用 x3 的情况下只需要5次乘法)

一般来说,求给定指数的最佳加法链是一个难题,因为没有已知的高效算法,所以最优链通常只用于小指数(比如,在編譯器中已经预先存储了小指数幂的最佳链)。不过,有一些启发式算法,虽然不是最优的,但是由于额外的簿记工作和内存使用量的增加而导致的乘法次数少于平方求幂。无论如何,乘法的次数永远不会比 Θ(log n) 增长得更慢,所以这些算法只能减小平方求幂的渐进复杂度的常数因子。

参见

  • 模幂运算
  • 向量加法链英语Vectorial addition chain
  • 蒙哥马利算法
  • 非相邻形式英语Non-adjacent form
  • 加法链英语Addition chain

注释

  1. ^ In this line, the loop finds the longest string of length less than or equal to 'k' which ends in a non zero value. And not all odd powers of 2 up to   need be computed and only those specifically involved in the computation need be considered.

参考文献

  1. ^ 1.0 1.1 Cohen, H.; Frey, G. (编). Handbook of Elliptic and Hyperelliptic Curve Cryptography. Discrete Mathematics and Its Applications. Chapman & Hall/CRC. 2006. ISBN 9781584885184. 
  2. ^ Montgomery, Peter L. Speeding the Pollard and Elliptic Curve Methods of Factorization (PDF). Math. Comput. 1987, 48 (177): 243–264 [2018-02-17]. (原始内容 (PDF)于2018-01-27). 

平方求幂, 在数学和程序设计中, 平方求冪, 英語, exponentiating, squaring, 或快速冪是快速计算一个数, 或更一般地说, 一个半群的元素, 如多項式或方阵, 的大正整数乘幂的一般方法, 这些算法可以非常通用, 例如用在模算數或矩阵幂, 对于通常使用加性表示法的半群, 如密码学中使用的椭圆曲线, 这种方法也称为double, 目录, 基本方法, 计算复杂度, 2k法, 滑动窗口法, 蒙哥马利阶梯法, 固定基底的幂, 姚期智的方法, 欧几里得法, 更多应用, 示例实现, 通过2的幂进行计算,. 在数学和程序设计中 平方求冪 英語 exponentiating by squaring 或快速冪是快速计算一个数 或更一般地说 一个半群的元素 如多項式或方阵 的大正整数乘幂的一般方法 这些算法可以非常通用 例如用在模算數或矩阵幂 对于通常使用加性表示法的半群 如密码学中使用的椭圆曲线 这种方法也称为double and add 目录 1 基本方法 2 计算复杂度 3 2k法 4 滑动窗口法 5 蒙哥马利阶梯法 6 固定基底的幂 6 1 姚期智的方法 6 2 欧几里得法 7 更多应用 8 示例实现 8 1 通过2的幂进行计算 8 1 1 运行实例 计算 310 8 1 2 运行实例 计算 310 8 2 幂的乘积的计算 8 2 1 例子 8 2 2 使用变换 8 2 3 例子 9 用有符号数字重新编码 10 替代方法及推广 11 参见 12 注释 13 参考文献基本方法 编辑该方法是基于观察到 对于正整数n displaystyle n 可知 x n x x 2 n 1 2 if n is odd x 2 n 2 if n is even displaystyle x n begin cases x x 2 frac n 1 2 amp mbox if n mbox is odd x 2 frac n 2 amp mbox if n mbox is even end cases 该方法使用指数的位 二进制的位 即bit 下文称为 位 来确定计算哪些幂 此例显示如何使用此方法计算 x 13 displaystyle x 13 幂指数13的二进制为1101 这些位按照从左到右的顺序使用 指数有4位 所以有4次迭代 首先 将结果初始化为1 r 1 x 0 displaystyle r leftarrow 1 x 0 r r 2 x 0 displaystyle r leftarrow r 2 x 0 第1位 1 所以计算 r r x x 1 displaystyle r leftarrow r cdot x x 1 r r 2 x 2 displaystyle r leftarrow r 2 x 2 第2位 1 所以计算 r r x x 3 displaystyle r leftarrow r cdot x x 3 r r 2 x 6 displaystyle r leftarrow r 2 x 6 第3位 0 所以这一步什么都不做 r r 2 x 12 displaystyle r leftarrow r 2 x 12 第4位 1 所以计算 r r x x 13 displaystyle r leftarrow r cdot x x 13 这可以按照下面的递归算法来实现 Function exp by squaring x n if n lt 0 then return exp by squaring 1 x n else if n 0 then return 1 else if n 1 then return x else if n is even then return exp by squaring x x n 2 else if n is odd then return x exp by squaring x x n 1 2 尽管不是尾调用 但是通过引入辅助函数 该算法可以被重写成尾递归算法 Function exp by squaring x n exp by squaring2 1 x n Function exp by squaring2 y x n if n lt 0 then return exp by squaring2 y 1 x n else if n 0 then return y else if n 1 then return x y else if n is even then return exp by squaring2 y x x n 2 else if n is odd then return exp by squaring2 x y x x n 1 2 该算法的迭代版本的辅助空间是有界的 代码如下 Function exp by squaring iterative x n if n lt 0 then x 1 x n n if n 0 then return 1 y 1 while n gt 1 do if n is even then x x x n n 2 else y x y x x x n n 1 2 return x y c 实现 非递归 返回p n displaystyle p n 对M o d displaystyle Mod 求模 long long power long long p long long n long long ans 1 while n if n amp 1 ans ans p Mod p p p Mod n gt gt 1 return ans 计算复杂度 编辑简要分析表明此算法用了 log 2 n displaystyle lfloor log 2 n rfloor 次平方 以及至多 log 2 n displaystyle lfloor log 2 n rfloor 次乘法 其中 displaystyle lfloor rfloor 表示向下取整函数 更确切地说 做乘法的次数比 n 的二进制展开的次数要少一次 对于 n 大于4左右的时候 这种算法在计算上就已经比天真地将它与自身重复地相乘更高效了 每次平方的结果大约是前一次结果的两倍 因此 如果两个 d 位数的相乘的实现要进行 O dk 次计算 其中 k 为一固定值 那么计算 xn 的复杂度为 i 0 O log n 2 i O log x k O n log x k displaystyle sum limits i 0 O log n 2 i O log x k O n log x k 2k法 编辑此算法先把指数展开成 2k 形式 然后再计算 xn 的值 它在1939年由Brauer首次提出 在下面的算法中 使用以下函数 f 0 k 0 和 f m s u 其中 m u 2s u 为奇数 算法 输入 G 的一个元素 x 参数 k gt 0 一个非零整数 n nl 1 nl 2 n0 2k 以及预计算的值 x 3 x 5 x 2 k 1 displaystyle x 3 x 5 x 2 k 1 输出 G 中的元素 xny 1 i l 1 while i gt 0 do s u f ni for j 1 to k s do y y2 y y xu for j 1 to s do y y2 i i 1 return y 为了获得最佳效率 k 应该是满足 log n lt k k 1 2 2 k 2 k 1 k 2 1 displaystyle log n lt frac k k 1 cdot 2 2k 2 k 1 k 2 1 的最小整数 1 滑动窗口法 编辑此方法是 2k 法的更高效的变体 例如 要计算398次幂 二进制展开为 110 001 110 2 采用长度为3的窗 使用 2k 法 需要计算 1 x3 x6 x12 x24 x48 x49 x98 x99 x198 x199 x398 但也可以计算 1 x3 x6 x12 x24 x48 x96 x192 x198 x199 x398 这就会省下一次乘法 相当于是计算 110 001 110 n2 的值以下是一般算法 算法 输入 G的元素 x 非负整数 n nl 1 nl 2 n0 2 一个参数 k gt 0 以及预计算的值 x 3 x 5 x 2 k 1 displaystyle x 3 x 5 x 2 k 1 输出 元素 xn G算法 y 1 i l 1 while i gt 1 do if ni 0 then y y2 i i 1 else s max i k 1 0 while ns 0 do s s 1 notes 1 for h 1 to i s 1 do y y2 u ni ni 1 ns 2 y y xu i s 1 return y蒙哥马利阶梯法 编辑求幂的许多算法都不提供对旁路攻击的防护 也就是说 监测到乘方运算的攻击者可以 部分 还原所计算的指数 就如众多公钥加密系统中那样 如果指数需要保密的话 这就是个问题了 一个叫做蒙哥马利阶梯 2 的方法解决了这个问题 给定一个非零正整数的二进制展开 n nk 1 n0 2 其中 nk 1 1 可以以下面方式计算 xn x1 x x2 x2 for i k 2 to 0 do If ni 0 then x2 x1 x2 x1 x12 else x1 x1 x2 x2 x22 return x1 该算法会执行一系列固定的操作 复杂度log n 无论每一位的具体值如何 指数中的每一位都会进行乘法和平方 蒙哥马利阶梯法的这种具体实现还无法抵御缓存时序攻击 英语 timing attack 当根据秘密指数的位值访问不同的变量时 内存访问延迟仍可能被攻击者观察到 固定基底的幂 编辑当基底固定而指数变化时 可以使用几种方法来计算 xn 可以看出 预计算在这些算法中起着关键作用 姚期智的方法 编辑 姚期智的方法与 2k 法不同 是把指数以 b 2k 为基底展开 并按上面的算法进行计算 令 n ni b bi 为整数 把指数 n 写成 n i 0 w 1 n i b i displaystyle n sum i 0 w 1 n i b i 其中对所有 i 0 w 1 displaystyle i in 0 w 1 都有 0 n i lt h displaystyle 0 leqslant n i lt h 令 xi xbi 该算法使用等式 x n i 0 w 1 x i n i j 1 h 1 n i j x i j displaystyle x n prod i 0 w 1 x i n i prod j 1 h 1 bigg prod n i j x i bigg j 给定 G 的元素 x 指数 n 写成上述形式 并且预先计算 xb0 xbw 1 的值 元素 xn 就可以用下面的算法计算了 y 1 u 1 and j h 1 while j gt 0 do for i 0 to w 1 do if ni j then u u xbi y y u j j 1 return y 如果令 h 2k bi hi 那么这些 ni 就是 n 以 h 为基的每一位 姚期智的方法是把之前的那些 xi 收集到 u 中 which appear to the highest power h 1 displaystyle h 1 in the next round those with power h 2 displaystyle h 2 are collected in u as well etc 变量 y 被原始的 u 乘了 h 1 displaystyle h 1 次 内第二高的指数乘了 h 2 displaystyle h 2 次 该算法计算 xn 要用 w h 2 displaystyle w h 2 次乘法 存储 w 1 displaystyle w 1 个元素 1 欧几里得法 编辑 欧几里德法首先在P D Rooij的 使用预计算和向量加法链的高效求幂 Efficient exponentiation using precomputation and vector addition chains 中介绍 这种计算群 G 中 x n displaystyle x n n 为自然数 的方法是 递归地使用下面的等式 x 0 n 0 x 1 n 1 x 0 x 1 q n 0 x 1 n 1 mod n 0 displaystyle x 0 n 0 cdot x 1 n 1 left x 0 cdot x 1 q right n 0 cdot x 1 n 1 mod n 0 where q n 1 n 0 displaystyle q left lfloor frac n 1 n 0 right rfloor 换句话说 用指数 n1 与 n0 的欧几里得除法来返回商 q 和余数 n1 mod n0 给定群 G 中的基底元素 x 把指数 n displaystyle n 用姚期智的方法写出来 然后就可以用预计算的 l displaystyle l 个值 x b 0 x b l i displaystyle x b 0 x b l i 计算 x n displaystyle x n 了 Begin loop Find M 0 l 1 displaystyle M in left 0 l 1 right such that i 0 l 1 n M n i displaystyle forall i in left 0 l 1 right n M geq n i Find N 0 l 1 M displaystyle N in left left 0 l 1 right M right such that i 0 l 1 M n N n i displaystyle forall i in left left 0 l 1 right M right n N geq n i Break loop if n N 0 displaystyle n N 0 Let q n M n N displaystyle q left lfloor n M n N right rfloor and then let n N n M mod n N displaystyle n N left n M bmod n N right Compute recursively x M q displaystyle x M q and then let x N x N x M q displaystyle x N x N cdot x M q End loop Return x n x M n M displaystyle x n x M n M 该算法首先在 ni 中找到最大值 在找到集合 ni i M 中的最大值 然后递归求 xM 的 q 次幂 把这个值乘以 xN 赋值给 xN 把 nM 模 nN 的结果赋值给 nM 更多应用 编辑这一思路还可用于计算大指数幂除以一个数的余数 特别是在密码学中 在整数除以q的余数的环中计算幂是很有用处的 在群中计算整数幂也是很有用的 使用法则 Power x n Power x n 1 该方法对所有半群都适用 通常用于计算矩阵的幂 例如 如果使用朴素的方法 计算 13789722341 mod 2345 将花费很长时间以及大量的存储空间 计算 13789722341 并除以2345求余 即便使用更有效的方法也需要很长时间 求13789的平方 除以2345求余 将结果乘以13789 再求余 一直往下计算 这会需要 2 log 2 722340 40 displaystyle 2 log 2 722340 leq 40 次模乘 把 理解为 x y xy mod 2345 即相乘后取模 后 应用上面的平方求幂算法 只需要27次乘法和整数除法 所有这些都可以存储在单个机器字中 就可以完成计算了 示例实现 编辑通过2的幂进行计算 编辑 这是用Ruby写的上述算法的非递归实现 由于低级语言会将 n n 2 隐式向0取整 n n 1 对那些语言来说 就是冗余的步骤了 n 0 是n的二进制表示的最右边的位 所以如果它是1 则该数是奇数 如果它是零 则该数是偶数 它也是以2为模n的余数 def power x n result 1 while n nonzero if n 0 nonzero result x n 1 end x x n 2 end return result end 运行实例 计算 310 编辑 parameter x 3 parameter n 10 result 1 Iteration 1 n 10 gt n is even x x2 32 9 n n 2 5 Iteration 2 n 5 gt n is odd gt result result x 1 x 1 32 9 n n 1 4 x x2 92 34 81 n n 2 2 Iteration 3 n 2 gt n is even x x2 812 38 6561 n n 2 1 Iteration 4 n 1 gt n is odd gt result result x 32 38 310 9 6561 59049 n n 1 0 return result 运行实例 计算 310 编辑 result 3 bin 1010 Iteration for digit 2 result result2 32 9 1010bin Digit equals 0 Iteration for digit 3 result result2 32 2 34 81 1010bin Digit equals 1 gt result result 3 32 2 3 35 243 Iteration for digit 4 result result2 32 2 3 2 310 59049 1010bin Digit equals 0 return result JavaScript Demonstration http home mnet online de wzwz de temp ebs en htm 页面存档备份 存于互联网档案馆 幂的乘积的计算 编辑 平方求幂也可用于计算2个或多个幂的乘积 如果基础群或半群是可交换的 那么常常可以通过同时计算乘积来减少乘法的次数 例子 编辑 式子 a7 b5 可以分三步计算 a 2 a 2 a 计算 a7 需要四次乘法 b 2 2 b 计算 b5 需要三次乘法 a7 b5 计算二者乘积需要一次乘法 所以总共需要八次乘法 更快的解法是同时计算这两个幂 a b 2 a 2 a b总共只需要6次乘法 注意 a b 计算了两次 结果可以在第一次计算后存储 这将乘法计数减少到5次 有数字的例子 27 35 2 3 2 2 2 2 3 62 2 2 6 722 6 31 104如果至少有两个指数大于1的话 同时计算幂就会比单独计算减少乘法次数 使用变换 编辑 如果表达式在计算前进行变换 上面的例子 a7 b5 也可以只用5次乘法就计算出来 a7 b5 a2 ab 5 其中 ab a b ab a b 一次乘法 a2 ab 5 ab 2 a 2 ab 四次乘法 这个变换可以推广成下面的方案 对于计算 aA bB mM nN 首先 定义 ab a b abc ab c 然后 计算变换后的表达式 aA B abB C abc mM N abc mnN在计算之前进行变换通常会减少乘法计数 但在某些情况下也会增加计数 请参见下面最后一个示例 因此在使用变换后的表达式进行计算之前 最好检查一下乘法的次数 例子 编辑 对于下面的表达式 表中显示了分开计算每个幂 在不进行变换的情况下同时进行计算 以及在变换后同时进行计算的乘法次数 例子 a7 b5 c3 a5 b5 c3 a7 b4 c1分开计算 a 2 a 2 a b 2 2 b c 2 c 11次乘法 a 2 2 a b 2 2 b c 2 c 10次乘法 a 2 a 2 a b 2 2 c 8次乘法 同时计算 a b 2 a c 2 a b c 8次乘法 a b 2 c 2 a b c 7次乘法 a b 2 a 2 a c 6次乘法 变换 a 2 ab a b abc ab c 2次乘法 a 2 ab a b abc ab c 2次乘法 a 2 ab a b abc ab c 2次乘法 之后的计算 a ab abc 2 abc 4次乘法 总共6次 ab abc 2 abc 3次乘法 总共5次 a ab 2 a ab abc 5次乘法 总共7次 用有符号数字重新编码 编辑在某些计算中 如果允许负系数 也就会需要用基底的倒数 的话 只要在 G 中计算倒数很快或者已经预先计算 求幂会更加高效 例如 当计算 x2k 1 时 二进制方法需要 k 1 次乘法和 k 1 次平方 不过可以用 k 次平方得到 x2k 然后乘以 x 1 得到 x2k 1 为此 定义以 b 为基数的整数 n 的有符号数字表示 英语 signed digit representation 为 n i 0 l 1 n i b i with n i lt b displaystyle n sum i 0 l 1 n i b i text with n i lt b 有符号二进制表示也就是选取 b 2 n i 1 0 1 displaystyle n i in 1 0 1 的表示法 记为 n l 1 n 0 s displaystyle n l 1 dots n 0 s 有多种计算这种表示的方法 该表示不是唯一的 例如 取 n 478 10 1 1100 1 10 s displaystyle 10 bar 1 1100 bar 1 10 s 和 100 1 1000 1 0 s displaystyle 100 bar 1 1000 bar 1 0 s 给出了两个不同的有符号二进制表示 其中 1 displaystyle bar 1 表示 1 由于在二进制方法中 n 的基2表示的每个非零项都要计算乘法 因此感兴趣的是找到非零项数量最少的有符号二进制表示 即具有最小汉明重量的表示 有一种方法是计算非相邻形式 英语 non adjacent form 简称NAF 的有符号二进制表示 它满足对所有 i 0 displaystyle i geqslant 0 n i n i 1 0 displaystyle n i n i 1 0 记为 n l 1 n 0 NAF displaystyle n l 1 dots n 0 text NAF 例如 478的NAF表示为 1000 1 000 1 0 NAF displaystyle 1000 bar 1 000 bar 1 0 text NAF 这种表示总是有最小的汉明重量 下面的简单算法可以计算 n l n l 1 0 displaystyle n l n l 1 0 的整数 n n l n l 1 n 0 2 displaystyle n n l n l 1 dots n 0 2 的NAF表示 c 0 0 displaystyle c 0 0 for i 0 to l 1 do c i 1 1 2 c i n i n i 1 displaystyle c i 1 left lfloor frac 1 2 c i n i n i 1 right rfloor n i c i n i 2 c i 1 displaystyle n i c i n i 2c i 1 return n l 1 n 0 NAF displaystyle n l 1 dots n 0 text NAF Koyama和Tsuruoka的另一种算法并不要求 n i n i 1 0 displaystyle n i n i 1 0 这样的条件 它仍然可以让汉明重量最小化 替代方法及推广 编辑主条目 加法链求幂 平方求幂可以看作是一个次优的加法链求幂 英语 addition chain exponentiation 算法 它通过由重复指数加倍 平方 和指数递增 乘以 x 组成的加法链 英语 addition chain 来计算指数 更一般地 如果允许任何先前计算的指数相加 通过乘以 x 的幂 有时可以让求幂运算的乘法次数更少 但通常使用更多的内存 n 15 时的最少次数 a 15 x x x x 2 2 2 displaystyle a 15 x times x times x times x 2 2 2 平方求幂 6次乘法 a 15 x 3 x 3 2 2 displaystyle a 15 x 3 times x 3 2 2 最优加法链 在复用 x3 的情况下只需要5次乘法 一般来说 求给定指数的最佳加法链是一个难题 因为没有已知的高效算法 所以最优链通常只用于小指数 比如 在編譯器中已经预先存储了小指数幂的最佳链 不过 有一些启发式算法 虽然不是最优的 但是由于额外的簿记工作和内存使用量的增加而导致的乘法次数少于平方求幂 无论如何 乘法的次数永远不会比 8 log n 增长得更慢 所以这些算法只能减小平方求幂的渐进复杂度的常数因子 参见 编辑模幂运算 向量加法链 英语 Vectorial addition chain 蒙哥马利算法 非相邻形式 英语 Non adjacent form 加法链 英语 Addition chain 注释 编辑 In this line the loop finds the longest string of length less than or equal to k which ends in a non zero value And not all odd powers of 2 up to x 2 k 1 displaystyle x 2 k 1 need be computed and only those specifically involved in the computation need be considered 参考文献 编辑 1 0 1 1 Cohen H Frey G 编 Handbook of Elliptic and Hyperelliptic Curve Cryptography Discrete Mathematics and Its Applications Chapman amp Hall CRC 2006 ISBN 9781584885184 Montgomery Peter L Speeding the Pollard and Elliptic Curve Methods of Factorization PDF Math Comput 1987 48 177 243 264 2018 02 17 原始内容存档 PDF 于2018 01 27 取自 https zh wikipedia org w index php title 平方求幂 amp oldid 69229661, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。