同余幂的求解算法
1. 问题描述
同余幂,公式表示为bn mod m,即b的n次方对m取模。
2. 算法求解
2.1. 求解方法1
在日常工作中,可能会需要快速的求出同余幂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 := 1 power := b mod m for i:=0 to k-1 begin if Ai=1 then x :=(x * power) mod m power := (power * power) mod m end {x 等于 bn mod m} |
下面是C++算法,VC6下通过编译。红色部分与参考的代码有出入,一些地方是为了通过编译,一些地方是对代码性能上的优化,请读者留意。
#include <iostream> #include <vector> using namespace std;
int ModularExponentiation(int base, int exp_in_bin, int modular); vector<short> baseBexpansion(int num, short b);
void main(){ //测试,2413的16进制展开应该是96D //因为没有修改显示,所以会显示成9613 vector<short> a = baseBexpansion(2413, 16); //用迭代器显示结果 for(vector<short>::iterator it = a.begin(); it != a.end(); it++){ cout<<*it; }
cout<<endl; //测试数据,981^937 mod 2537的结果应该是704 int x=ModularExponentiation(981, 937,2537); cout<<x<<endl; }
/** * 计算 base^exp mod modular这个同余幂的值 * base:底数 * exp_in_bin:指数 * modular:模 * return: 同余幂 */ int ModularExponentiation(int base, int exp, int modular){ //把exp进行二进制展开 vector<short> 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<short> baseBexpansion(int num, short b){ int q = num; vector<short> a; while(q != 0){ a.push_back(q % b); q /= b; }
//反转a int 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; } } |
3. 参考文献
同余幂的原理和C++实现,附赠一个10进制数转换为任意进制的数组的算法.http://blog.csdn.net/cecilulysess/archive/2009/11/12/4801969.aspx
同余幂与康托展开.http://bomb23.blogbus.com/logs/42037791.html