在日常工作中,可能会需要快速的求出同余幂bn mod m,其中b,n,m都是比较大的整数。例如取b=12345678,n=456789,直接计算显然是不可行的,可以把n按二进制展开,则n=456789就变成了1101111100001010101,这样每次只需要求b mod m,b2 mod m,... b2^(k-1) mod m,然后把对应位置上的二进制是1的项乘起来,每次乘完后求除m的余数即可,大大降低了计算的复杂度。在《离散数学及其应用》里介绍了这种方法,用于密码学中。伪代码如下:procedure modular exponentiation(b:整数,n=(A(K-1)A(K-2)...A1A0)2(表示2进制展开),m:正整数)x := 1power := b mod mfor i:=0 to k-1beginif Ai=1 then x :=(x * power) mod mpower := (power * power) mod mend{x 等于 bn mod m}下面是C++算法,VC6下通过编译。红 {MOD}部分与参考的代码有出入,一些地方是为了通过编译,一些地方是对代码性能上的优化,请读者留意。#include #include using namespace std;int ModularExponentiation(int base, int exp_in_bin, int modular);vector baseBexpansion(int num, short b);void main(){//测试,2413的16进制展开应该是96D//因为没有修改显示,所以会显示成9613vector a = baseBexpansion(2413, 16);//用迭代器显示结果for(vector::iterator it = a.begin(); it != a.end(); it++){cout<<*it;}cout<//测试数据,981^937 mod 2537的结果应该是704int x=ModularExponentiation(981, 937,2537);cout<}/*** 计算 base^exp mod modular这个同余幂的值* base:底数* exp_in_bin:指数* modular:模* return: 同余幂*/int ModularExponentiation(int base, int exp, int modular){//把exp进行二进制展开vector n = baseBexpansion(exp, 2);int x = 1; //x = base^exp mod modular;int power = base % modular;for(int i = n.size() - 1; i > -1 ; i --){if( n[i] ) { //if n[i] == i//从二进制展开后的最右端开始求x = (x * power)% modular;}//求b^(2^(k-1)) mod m的值power = (power * power) % modular;}return x;}/*** 计算数字num的b进制展开形式的数组* num:将被展开的数字* b:数字展开的基* return:数字展开后的向量,按照从左往右的顺序存储,如13的二进制展开为1101,存储的顺序也是{1,1,0,1}*/vector baseBexpansion(int num, short b){int q = num;vector a;while(q != 0){a.push_back(q % b);q /= b;}//反转aint size = a.size();int n = size/2;int temp = 0;for(int i = 0; i < n; i ++){temp = a[i];a[i] = a[size-1-i];a[size-1-i] = temp;}return a;}结论:该算法把求b的n次幂换成了求某个数的2次幂形式,大大降低了计算的复杂度。
2.2. 求解方法2
递归求解算法,VC6下已通过编译。int ModularExponentiation(int b, int n, int m){if (n == 0)return 1;if (n == 1)return (b % m);if (n % 2 > 0) {return (b * ModularExponentiation(b, n - 1, m)) % m;} else {int temp;temp = ModularExponentiation(b, n / 2, m);return (temp * temp) % m;}}