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; } 

计算复杂度 编辑

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

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

 

编辑

此算法先把指数展开成   形式,然后再计算   的值。它在1939年由Brauer首次提出。在下面的算法中,使用以下函数   ,其中    为奇数。

算法:

输入
G 的一个元素  ,参数  ,一个非零整数   以及预计算的值  
输出
G 中的元素  
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 

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

 

的最小整数。[1]

滑动窗口法 编辑

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

以下是一般算法:

算法:

输入
G的元素  ,非负整数  ,一个参数  ,以及预计算的值  
输出
元素  

算法:

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]的方法解决了这个问题。

给定一个非零正整数的二进制展开  (其中  ),可以以下面方式计算  

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

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

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

固定基底的幂 编辑

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

姚期智的方法 编辑

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

把指数   写成

  其中对所有   都有  

 。该算法使用等式

 

给定   的元素  ,指数   写成上述形式,并且预先计算   的值,元素   就可以用下面的算法计算了。

 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 

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

欧几里得法 编辑

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

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

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

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

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

该算法首先在   中找到最大值,在找到集合   中的最大值。 然后递归求    次幂,把这个值乘以  ,赋值给  ;把    的结果赋值给  

更多应用 编辑

这一思路还可用于计算大指数幂除以一个数的余数。特别是在密码学中,在整数除以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次)

用有符号数字重新编码 编辑

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

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

 

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

  for i = 0 to l - 1 do     return   

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

替代方法及推广 编辑

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

  (平方求幂,6次乘法)
  (最优加法链,在复用   的情况下只需要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, 目录, 基本方法, 计算复杂度, uniq, postmath, 00000018, qinu, 滑动窗口法, 蒙哥马利阶梯法, 固定基底的幂, 姚期智的方法, 欧几. 在数学和程序设计中 平方求冪 英語 exponentiating by squaring 或快速冪是快速计算一个数 或更一般地说 一个半群的元素 如多項式或方阵 的大正整数乘幂的一般方法 这些算法可以非常通用 例如用在模算數或矩阵幂 对于通常使用加性表示法的半群 如密码学中使用的椭圆曲线 这种方法也称为double and add 目录 1 基本方法 2 计算复杂度 3 UNIQ postMath 00000018 QINU 法 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 nbsp 可知 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 nbsp 该方法使用指数的位 二进制的位 即bit 下文称为 位 来确定计算哪些幂 此例显示如何使用此方法计算 x 13 displaystyle x 13 nbsp 幂指数13的二进制为1101 这些位按照从左到右的顺序使用 指数有4位 所以有4次迭代 首先 将结果初始化为1 r 1 x 0 displaystyle r leftarrow 1 x 0 nbsp r r 2 x 0 displaystyle r leftarrow r 2 x 0 nbsp 第1位 1 所以计算 r r x x 1 displaystyle r leftarrow r cdot x x 1 nbsp r r 2 x 2 displaystyle r leftarrow r 2 x 2 nbsp 第2位 1 所以计算 r r x x 3 displaystyle r leftarrow r cdot x x 3 nbsp r r 2 x 6 displaystyle r leftarrow r 2 x 6 nbsp 第3位 0 所以这一步什么都不做 r r 2 x 12 displaystyle r leftarrow r 2 x 12 nbsp 第4位 1 所以计算 r r x x 13 displaystyle r leftarrow r cdot x x 13 nbsp 这可以按照下面的递归算法来实现 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 nbsp 对M o d displaystyle Mod nbsp 求模 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 nbsp 次平方 以及至多 log 2 n displaystyle lfloor log 2 n rfloor nbsp 次乘法 其中 displaystyle lfloor rfloor nbsp 表示向下取整函数 更确切地说 做乘法的次数比 n displaystyle n nbsp 的二进制展开的次数要少一次 对于 n displaystyle n nbsp 大于4左右的时候 这种算法在计算上就已经比天真地将它与自身重复地相乘更高效了 每次平方的结果大约是前一次结果的两倍 因此 如果两个 d displaystyle d nbsp 位数的相乘的实现要进行 O d k displaystyle mathrm O d k nbsp 次计算 其中 k displaystyle k nbsp 为一固定值 那么计算 x n displaystyle x n nbsp 的复杂度为 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 nbsp 2 k displaystyle 2 k 法 编辑此算法先把指数展开成 2 k displaystyle 2 k nbsp 形式 然后再计算 x n displaystyle x n nbsp 的值 它在1939年由Brauer首次提出 在下面的算法中 使用以下函数 f 0 k 0 displaystyle f 0 k 0 nbsp 和f m s u displaystyle f m s u nbsp 其中 m u 2 s displaystyle m u cdot 2 s nbsp u displaystyle u nbsp 为奇数 算法 输入 G 的一个元素 x displaystyle x nbsp 参数 k gt 0 displaystyle k gt 0 nbsp 一个非零整数 n n l 1 n l 2 n 0 2 k displaystyle n n l 1 n l 2 ldots n 0 2 k nbsp 以及预计算的值 x 3 x 5 x 2 k 1 displaystyle x 3 x 5 x 2 k 1 nbsp 输出 G 中的元素 x n displaystyle x n nbsp y 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 displaystyle k nbsp 应该是满足 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 nbsp 的最小整数 1 滑动窗口法 编辑此方法是 2 k displaystyle 2 k nbsp 法的更高效的变体 例如 要计算398次幂 二进制展开为 110 001 110 2 采用长度为3的窗 使用 2 k displaystyle 2 k nbsp 法 需要计算 1 x 3 x 6 x 12 x 24 x 48 x 49 x 98 x 99 x 198 x 199 x 398 displaystyle x 3 x 6 x 12 x 24 x 48 x 49 x 98 x 99 x 198 x 199 x 398 nbsp 但也可以计算 1 x 3 x 6 x 12 x 24 x 48 x 49 x 96 x 192 x 198 x 199 x 398 displaystyle x 3 x 6 x 12 x 24 x 48 x 49 x 96 x 192 x 198 x 199 x 398 nbsp 这就会省下一次乘法 相当于是计算 110 001 110 n2 的值以下是一般算法 算法 输入 G的元素 x displaystyle x nbsp 非负整数 n n l 1 n l 2 n 0 2 displaystyle n n l 1 n l 2 ldots n 0 2 nbsp 一个参数 k gt 0 displaystyle k gt 0 nbsp 以及预计算的值 x 3 x 5 x 2 k 1 displaystyle x 3 x 5 x 2 k 1 nbsp 输出 元素 x n G displaystyle x n in G nbsp 算法 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 n k 1 n 0 2 displaystyle n n k 1 ldots n 0 2 nbsp 其中 n k 1 1 displaystyle n k 1 1 nbsp 可以以下面方式计算 x n displaystyle x n nbsp 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 displaystyle log n nbsp 无论每一位的具体值如何 指数中的每一位都会进行乘法和平方 蒙哥马利阶梯法的这种具体实现还无法抵御缓存时序攻击 英语 timing attack 当根据秘密指数的位值访问不同的变量时 内存访问延迟仍可能被攻击者观察到 固定基底的幂 编辑当基底固定而指数变化时 可以使用几种方法来计算 x n displaystyle x n nbsp 可以看出 预计算在这些算法中起着关键作用 姚期智的方法 编辑 姚期智的方法与 2 k displaystyle 2 k nbsp 法不同 是把指数以 b 2 k displaystyle b 2 k nbsp 为基底展开 并按上面的算法进行计算 令 n displaystyle n nbsp n i displaystyle n i nbsp b displaystyle b nbsp b i displaystyle b i nbsp 为整数 把指数 n displaystyle n nbsp 写成 n i 0 w 1 n i b i displaystyle n sum i 0 w 1 n i b i nbsp 其中对所有 i 0 w 1 displaystyle i in 0 w 1 nbsp 都有 0 n i lt h displaystyle 0 leqslant n i lt h nbsp 令 x i x b i displaystyle x i x b i nbsp 该算法使用等式 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 nbsp 给定 G displaystyle G nbsp 的元素 x displaystyle x nbsp 指数 n displaystyle n nbsp 写成上述形式 并且预先计算 x b 0 x b w 1 displaystyle x b 0 ldots x b w 1 nbsp 的值 元素 x n displaystyle x n nbsp 就可以用下面的算法计算了 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 2 k displaystyle h 2 k nbsp b i h i displaystyle b i h i nbsp 那么这些 n i displaystyle n i nbsp 就是 n displaystyle n nbsp 以 h displaystyle h nbsp 为基的每一位 姚期智的方法是把之前的那些 x i displaystyle x i nbsp 收集到 u displaystyle u nbsp 中 which appear to the highest power h 1 displaystyle h 1 nbsp in the next round those with power h 2 displaystyle h 2 nbsp are collected in u displaystyle u nbsp as well etc 变量 y displaystyle y nbsp 被原始的 u displaystyle u nbsp 乘了 h 1 displaystyle h 1 nbsp 次 内第二高的指数乘了 h 2 displaystyle h 2 nbsp 次 该算法计算 x n displaystyle x n nbsp 要用 w h 2 displaystyle w h 2 nbsp 次乘法 存储 w 1 displaystyle w 1 nbsp 个元素 1 欧几里得法 编辑 欧几里德法首先在P D Rooij的 使用预计算和向量加法链的高效求幂 Efficient exponentiation using precomputation and vector addition chains 中介绍 这种计算群 G 中 x n displaystyle x n nbsp n displaystyle n nbsp 为自然数 的方法是 递归地使用下面的等式 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 nbsp where q n 1 n 0 displaystyle q left lfloor frac n 1 n 0 right rfloor nbsp 换句话说 用指数 n 1 displaystyle n 1 nbsp 与 n 0 displaystyle n 0 nbsp 的欧几里得除法来返回商 q displaystyle q nbsp 和余数 n 1 mod n 0 displaystyle n 1 bmod n 0 nbsp 给定群 G 中的基底元素 x displaystyle x nbsp 把指数 n displaystyle n nbsp 用姚期智的方法写出来 然后就可以用预计算的 l displaystyle l nbsp 个值 x b 0 x b l i displaystyle x b 0 x b l i nbsp 计算 x n displaystyle x n nbsp 了 Begin loop Find M 0 l 1 displaystyle M in left 0 l 1 right nbsp such that i 0 l 1 n M n i displaystyle forall i in left 0 l 1 right n M geq n i nbsp Find N 0 l 1 M displaystyle N in left left 0 l 1 right M right nbsp 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 nbsp Break loop if n N 0 displaystyle n N 0 nbsp Let q n M n N displaystyle q left lfloor n M n N right rfloor nbsp and then let n N n M mod n N displaystyle n N left n M bmod n N right nbsp Compute recursively x M q displaystyle x M q nbsp and then let x N x N x M q displaystyle x N x N cdot x M q nbsp End loop Return x n x M n M displaystyle x n x M n M nbsp 该算法首先在 n i displaystyle n i nbsp 中找到最大值 在找到集合 n i i M displaystyle n i backslash i neq M nbsp 中的最大值 然后递归求 x M displaystyle x M nbsp 的 q displaystyle q nbsp 次幂 把这个值乘以 x N displaystyle x N nbsp 赋值给 x N displaystyle x N nbsp 把 n M displaystyle n M nbsp 模 n N displaystyle n N nbsp 的结果赋值给 n M displaystyle n M nbsp 更多应用 编辑这一思路还可用于计算大指数幂除以一个数的余数 特别是在密码学中 在整数除以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 nbsp 次模乘 把 理解为 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 displaystyle boldsymbol G nbsp 中计算倒数很快或者已经预先计算 求幂会更加高效 例如 当计算 x 2 k 1 displaystyle x 2 k 1 nbsp 时 二进制方法需要 k 1 displaystyle k 1 nbsp 次乘法和 k 1 displaystyle k 1 nbsp 次平方 不过可以用 k displaystyle k nbsp 次平方得到 x 2 k displaystyle x 2 k nbsp 然后乘以 x 1 displaystyle x 1 nbsp 得到 x 2 k 1 displaystyle x 2 k 1 nbsp 为此 定义以 b displaystyle b nbsp 为基数的整数 n displaystyle n nbsp 的有符号数字表示 英语 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 nbsp 有符号二进制表示也就是选取 b 2 displaystyle b 2 nbsp n i 1 0 1 displaystyle n i in 1 0 1 nbsp 的表示法 记为 n l 1 n 0 s displaystyle n l 1 dots n 0 s nbsp 有多种计算这种表示的方法 该表示不是唯一的 例如 取 n 478 displaystyle n 478 nbsp 10 1 1100 1 10 s displaystyle 10 bar 1 1100 bar 1 10 s nbsp 和 100 1 1000 1 0 s displaystyle 100 bar 1 1000 bar 1 0 s nbsp 给出了两个不同的有符号二进制表示 其中 1 displaystyle bar 1 nbsp 表示 1 由于在二进制方法中 n displaystyle n nbsp 的基2表示的每个非零项都要计算乘法 因此感兴趣的是找到非零项数量最少的有符号二进制表示 即具有最小汉明重量的表示 有一种方法是计算非相邻形式 英语 non adjacent form 简称NAF 的有符号二进制表示 它满足对所有 i 0 displaystyle i geqslant 0 nbsp n i n i 1 0 displaystyle n i n i 1 0 nbsp 记为 n l 1 n 0 NAF displaystyle n l 1 dots n 0 text NAF nbsp 例如 478的NAF表示为 1000 1 000 1 0 NAF displaystyle 1000 bar 1 000 bar 1 0 text NAF nbsp 这种表示总是有最小的汉明重量 下面的简单算法可以计算 n l n l 1 0 displaystyle n l n l 1 0 nbsp 的整数 n n l n l 1 n 0 2 displaystyle n n l n l 1 dots n 0 2 nbsp 的NAF表示 c 0 0 displaystyle c 0 0 nbsp 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 nbsp n i c i n i 2 c i 1 displaystyle n i c i n i 2c i 1 nbsp return n l 1 n 0 NAF displaystyle n l 1 dots n 0 text NAF nbsp Koyama和Tsuruoka的另一种算法并不要求 n i n i 1 0 displaystyle n i n i 1 0 nbsp 这样的条件 它仍然可以让汉明重量最小化 替代方法及推广 编辑主条目 加法链求幂 平方求幂可以看作是一个次优的加法链求幂 英语 addition chain exponentiation 算法 它通过由重复指数加倍 平方 和指数递增 乘以 x displaystyle x nbsp 组成的加法链 英语 addition chain 来计算指数 更一般地 如果允许任何先前计算的指数相加 通过乘以 x displaystyle x nbsp 的幂 有时可以让求幂运算的乘法次数更少 但通常使用更多的内存 n 15 displaystyle n 15 nbsp 时的最少次数 a 15 x x x x 2 2 2 displaystyle a 15 x times x times x times x 2 2 2 nbsp 平方求幂 6次乘法 a 15 x 3 x 3 2 2 displaystyle a 15 x 3 times x 3 2 2 nbsp 最优加法链 在复用 x 3 displaystyle x 3 nbsp 的情况下只需要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 nbsp 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 75851247, 维基百科,wiki,书籍,书籍,图书馆,

文章

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