2.7.2 快速模幕运算

幂运算非常简单,很容易计算。比如计算,可以列出,只需要计算15次乘法就能得到答案。但是如果指数是一个大数,比如1000000000 ,那么求这种高次幂的最小正整数模应该怎么办呢?对于这种大数,挨个计算就太复杂了,会降低加解密的效率。为了提高效率,就必须想办法在计算的过程中用最少的步骤来快速达到指定的指数。

想快速得到幂运算的结果就需要用到二进制。当指数使用二进制表示时,只有0和1可以作为系数出现,这意味着每个正整数都可以表示为2的不同幂的和。还是以为例,十进制转二进制的方法如例1.3.1所示。利用平方,可以快速得到结果:

pg41a

仅需4次计算就能得到结果。相比进行15次重复运算,大大节约了时间。

如果幂不是2的倍数呢?比如,应该如何计算?其实也很简单,拆分计算即可:

pg41b

这样也仅需6次就可以得到答案。

2.7.3 上面例子的计算较简单,不使用相关公式也可以计算。如果是)这种大数模的幂运算呢?在通常的运算过程中人们都不想处理大数,因为这时候计算太繁琐。此时可应用幂取模运算的办法。

解:第1步,将中的指数转化为二进制数。

用Python代码可写成:

 1  #二进制数
 2  number = 2641
 3  number_bin = bin(number)[2:]
 4  cov_number_bin = bin(number)[2:][::-1]
 5
 6  sum_number = ''
 7  for i in range(len(cov_number_bin)):
 8      if cov_number_bin[i] == '1':
 9          if sum_number == '':
10              sum_number += str(2**(i))
11          else:
12              sum_number += ' + ' + str(2**(i))
13  print(sum_number)

第2步,用重复平方(Repeated Squaring)得到幂的余。

因为,因此,得到3278564后继续使用作为的基本单位。不用直接计算,只需要计算。得到1631541后又可以继续应用在上,使得。以此类推,以减少运算量,得到所有的2次幂项的余:

第3步,将第1步得到的幂次相乘。

Python计算过程如下,速度比Python的运算符快,因为无须重复计算。下面的函数等同于Python内置函数pow(a,n,p)

 1  def fastExpMod(a, n, p):
 2      result = 1
 3      while n != 0:
 4          if (n&1) == 1:
 5              # ei = 1, then mul
 6              result = (result * a) % p
 7          n >>= 1
 8          # a, a^2, a^4, a^8, ... , a^(2^n)
 9          a = (a*a) % p
10      return result

因此,如果是正整数,计算的时间复杂度大约为

欧拉定理除了可以用于快速求大数幂运算的模,还可以用于求逆元。当时,因为根据欧拉定理,同乘可以得到,等式两边调换一下位置得到:

如果为素数,那么就很容易得到:

2.7.4 计算

解:计算。因为,且997是素数,所以:

计算。因为,所以可以用欧拉定理。但151255不是素数,所以需要计算。首先,因此可以很容易算出:

那么: