同余幂的求解算法(原)

同余幂的求解算法

 

1. 问题描述

同余幂,公式表示为bn mod m,即bn次方对m取模。

 

2. 算法求解

2.1. 求解方法1

在日常工作中,可能会需要快速的求出同余幂bn mod m,其中bnm都是比较大的整数。例如取b=12345678n=456789,直接计算显然是不可行的,可以把n按二进制展开,则n=456789就变成了1101111100001010101,这样每次只需要求b mod mb2 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(){

    //测试,241316进制展开应该是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;

}

 

/** 

 * 计算数字numb进制展开形式的数组

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

}

结论:该算法把求bn次幂换成了求某个数的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值