同余幂的原理和C++实现,附赠一个10进制数转换为任意进制的数组的算法。

   18世纪末,高斯这个大牛定义了所谓同余的概念,这个东西在离散数学里几乎到处都是,作用也多的没话说,特别是现在很多加密算法都有用到。而这个同余幂也是基于同余中的一个小知识,主要还是因为能够比较方便的计算非常大的整数的求幂再求模,所以比较不小心就会用到。所以今天有空就专门写了一个函数的形式,方便以后随时取用。同时,因为要进行快速同余幂的计算必须要使用对10进制数字的二进制展开,我也就顺便写了一个能够把10进制数据按任意基数展开的函数当然其实返回的是个vector而不是数组。  

 

这里先从同余简单开始介绍下:

  a≡b(mod m) iff(当且仅当)a mod m = b mod m。a≡b(mod m) 就读作:a模m同余b。这里,mod表示取模运算,比如3 mod 2就是3/2的余数1了。

  距离来说,比如17≡5(mod 6) ,17模6同余于5. 因为17/6余5,而5/6余5。

  

  同余关系和加法乘法的运算还是同构的,其实就是a + c b + d (mod m),和 a*c b*d(mod m);

 

下面说同余幂:

  我们经常会需要快速的求出bn mod m,其中 b n m都是比较大的整数,比如b=12345 n=5567,这样去直接计算显然是不可行的,所以我们把n进行二进制展开(就是转换为二进制)比如这个n就变成了1010110111111,这样每次只需要求b mod m,b2 mod m,... b2^(k-1) mod m,然后把对应位置上的二进制是1的项乘起来。在每次乘完以后求除m的余数即可。

 

int ModularExponentiation(int base, int exp_in_bin, int modular); vector<short> baseBexpansion(int num, short b); int 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, i = 0, temp = 0; vector<short> a; while(q != 0){ a.push_back(q % b); q /= b; } //反转a int size = a.size(); for(; i < size/2; i ++){ temp = a[i]; a[i] = a[size-1-i]; a[size-1-i] = temp; } return a; }

 

     实际上,因为这个算法里面,因为把求b的n次幂换成了求某个数的2次幂形式,渐而大大的降低了计算的复杂度,比如对于12345678987654321这样一个指数,它的二进制形式是:101011110111000101010001100010100100011111010010110001,所以最大要计算的数也不过是9007199254740992*9007199254740992= 81129638414606681695789005144064(实际上,这个计算的数决定于modular的值,当modular没有这么大的时候,显然不可能要算这么大的数字), 而原来要对一个b计算12345678987654321次幂,即时b是2,在超过5位数的次幂之后几乎就已经无法用我们c++的double类型计算了。

你可能感兴趣的:(同余幂的原理和C++实现,附赠一个10进制数转换为任意进制的数组的算法。)