幂模运算快速算法
幂模运算
2. 大数幂模与乘模运算•Montgomery 幂模算法在实现了vlong 类型后,大数的存储和四则运算的功能都完成了。
考虑到RSA 算法需要进行幂模运算,需要准备实现这些运算的方法。
所以写一个vlong 的友元,完成幂模运算功能。
幂模运算是RSA 算法中比重最大的计算,最直接地决定了RSA 算法的性能,针对快速幂模运算这一课题,西方现代数学家提出了很多的解决方案。
经查阅相关数学著作,发现通常都是依据乘模的性质n n b n a n b a mod ))mod ()mod ((mod )(⨯=⨯,先将幂模运算化简为乘模运算。
通常的分解习惯是指数不断的对半分,如果指数是奇数,就先减去一变成偶数,然后再对半分,例如求D=n C E mod ,E=15,可分解为如下6个乘模运算。
n C n C C C m od m od 21=⨯= n C n C C C m od m od 312=⨯= nC n C C C mod mod 6223=⨯= nC n C C C mod mod 734=⨯= nC n C C C mod mod 14445=⨯= nC n C C C mod mod 1556=⨯=归纳分析以上方法,对于任意指数E ,可采用如图2-4的算法流程计算 。
图2-4 幂模运算分解为乘模运算的一种流程按照上述流程,列举两个简单的幂模运算实例来形象的说明这种方法。
①求17mod215的值开始 D = 1 P = 2 mod 17 = 2 E = 15E奇数 D = DP mod n = 2 P = PP mod n = 4 E = (E-1)/2 =7E奇数 D = DP mod n = 8 P = PP mod n = 16 E = (E-1)/2 =3E奇数 D = DP mod n = 9 P = PP mod n = 1 E = (E-1)/2 =1E奇数 D = DP mod n = 9 P = PP mod n = 1 E = (E-1)/2 =0最终D = 9 即为所求。
蒙哥马利算法详解(一)
蒙哥马利算法详解(一)蒙哥马利算法详解什么是蒙哥马利算法蒙哥马利算法(Montgomery Algorithm)是一种用于大整数模幂运算的快速算法。
它在密码学中广泛应用,特别是在RSA加密和解密操作中。
原理概述蒙哥马利算法利用模幂运算中的数学性质,通过将大整数转换为蒙哥马利余数形式,从而加速运算。
转换为蒙哥马利余数1.选择合适的模数 R(一般为 2 的某次幂),使得模 R 的结果比较容易计算。
2.根据模数 R,计算出 R 的逆元R’,满足R × R’ ≡ 1 (modn),其中 n 为要计算的大整数。
3.将大整数 n 转换为蒙哥马利余数形式n’ = (n × R) mod n,即n’ = n × R mod n。
4.将指数 e 也转换为蒙哥马利余数形式e’ = (e × R) mod n。
蒙哥马利幂运算1.对于大整数 x,计算其蒙哥马利余数表示x’ = (x × R) modn。
2.初始化结果r’ = 1。
3.对于 e 的每一个二进制位 b,从高位到低位进行以下操作:•如果 b = 1,则将r’ 更新为r’ = (r’ × x’) mod n。
•将x’ 更新为x’ = (x’ × x’) mod n。
4.循环结束后,结果r’ 即为最终的蒙哥马利幂运算结果。
蒙哥马利逆转换1.将蒙哥马利幂运算结果r’ 转换为普通表示r = (r’ × R’mod n) mod n。
优势与应用•蒙哥马利算法的优势在于其快速的模幂运算速度,加速了RSA加密和解密操作。
•在实际应用中,蒙哥马利算法可用于优化RSA密钥生成和加密解密过程中的模幂运算,提升运算效率。
注意事项•在实现蒙哥马利算法时,需要注意大整数操作的溢出问题。
•进行蒙哥马利算法运算时,需要保证模数 n 是一个正整数。
该算法的运用在密码学中具有重要意义,大大提高了RSA算法的运算速度,值得进一步学习和研究。
基础算法—快速幂详解
基础算法—快速幂详解幂运算是⾮常常见的⼀种运算,求取,最容易想到的⽅法便是通过循环逐个累乘,其复杂度为,这在很多时候是不够快的,所以我们需要⼀种算法来优化幂运算的过程。
⼀、快速幂——反复平⽅法该怎样去加速幂运算的过程呢?既然我们觉得将幂运算分为n 步进⾏太慢,那我们就要想办法减少步骤,把其中的某⼀部分合成⼀步来进⾏。
⽐如,如果能被2整除,那我们可以先计算⼀半,得到的值,再把这个值平⽅得出结果。
这样做虽然有优化,但优化的程度很⼩,仍是线性的复杂度。
再⽐如,如果我们能找到,那我们就能把原来的运算优化成,只需要次运算就可以完成,效率⼤⼤提升。
可惜的是,这种条件显然太苛刻了,适⽤范围很⼩。
不过这给了我们⼀种思路,虽然我们很难找到,但我们能够找到。
这样,我们可以通过递推,在很短的时间内求出各个项的值。
我们都学习过进制与进制的转换,知道⼀个进制数的值可以表⽰为各个数位的值与权值之积的总和。
⽐如,2进制数,它的值可以表⽰为10进制的,即。
这完美地符合了上⾯的要求。
可以通过2进制来把转化成的序列之和,⽽2进制中第位(从右边开始计数,值为或是)则标记了对应的是否存在于序列之中。
譬如,为⼆进制的,他可以表⽰为,其中由于第⼆位为,项被舍去。
如此⼀来,我们只需要计算的值(这个序列中的项不⼀定都存在,由的⼆进制决定)并把它们乘起来即可完成整个幂运算。
借助位运算的操作,可以很⽅便地实现这⼀算法,其复杂度为。
typedef long long ll;ll mod;ll qpow(ll a, ll n)//计算a^n % mod{ll re = 1;while (n){if (n & 1)//判断n 的最后⼀位是否为1re = (re * a) % mod;n >>= 1;//舍去n 的最后⼀位a = (a * a) % mod;//将a 平⽅}return re % mod;}取模运算⼀般情况下是需要的,当然也可以省去。
快速模幂算法范文
快速模幂算法范文下面我们将详细介绍快速模幂算法的原理和步骤。
1.原理:假设要计算 a^b mod c 的值,其中 a 是底数,b 是指数,c 是模数。
快速模幂算法的基本思想是将指数 b 进行二进制拆分,然后利用二进制的运算特性进行迭代计算。
2.步骤:-将指数b转换为二进制形式。
例如,b=13(1101)。
- 初始化两个变量:result=1 作为最终结果的累积值,和 base=a作为当前底数。
- 从二进制数的最低位开始,如果最低位是1,则将当前底数乘以result,并对结果取模 c。
例如,result = 1 * a = a mod c。
- 将当前底数进行平方运算,并对结果取模 c,base = a^2 mod c。
-将指数b右移一位,相当于b=b/2-重复上述步骤,直到指数b的所有位都被处理完毕。
- 返回结果 result。
3.例子:让我们以a=3,b=13,c=7为例进行演示。
-将指数b的二进制表示为1101- 初始化 result=1,base=3- 最低位为1,将当前底数乘以 result,并对结果取模 c,result = 1 * 3 = 3 mod 7- 进行平方运算,base = 3^2 mod 7 = 9 mod 7 = 2 mod 7-右移一位,b=110。
-最低位为0,不进行计算。
- 进行平方运算,base = 2^2 mod 7 = 4 mod 7-右移一位,b=11- 最低位为1,将当前底数乘以 result,并对结果取模 c,result = 3 * 4 = 12 mod 7- 进行平方运算,base = 4^2 mod 7 = 16 mod 7 = 2 mod 7-右移一位,b=1- 最低位为1,将当前底数乘以 result,并对结果取模 c,result = 12 * 2 = 24 mod 7 = 3 mod 7- 进行平方运算,base = 2^2 mod 7 = 4 mod 7-右移一位,b=0。
幂运算常用的8个公式幂数口诀
幂运算常用的8个公式幂数口诀幂运算常用的8个公式是:1、同底数幂相乘;2、幂的乘方;3、积的乘方;4、同底数幂相除;5、a^(m+n)=a^m·a^n;6、a^mn=(a^m)·n;7、a^m·b^m=(ab)^m;8、a^(m-n)=a^m÷a^n(a≠0)。
幂运算常用的8个公式幂运算常用的8个公式是:1、同底数幂相乘:a^m·a^n=a^(m+n)。
2、幂的乘方:(a^m)n=a^mn。
3、积的乘方:(ab)^m=a^m·b^m。
4、同底数幂相除:a^m÷a^n=a^(m-n)(a≠0)。
5、a^(m+n)=a^m·a^n。
6、a^mn=(a^m)·n。
7、a^m·b^m=(ab)^m。
8、a^(m-n)=a^m÷a^n(a≠0)。
幂数口诀指数加减底不变,同底数幂相乘除。
指数相乘底不变,幂的乘方要清楚。
积商乘方原指数,换底乘方再乘除。
非零数的零次幂,常值为1不糊涂。
负整数的指数幂,指数转正求倒数。
看到分数指数幂,想到底数必非负。
乘方指数是分子,根指数要当分母。
幂运算是什么意思1、幂运算是一种关于幂的数学运算。
掌握正整数幂的运算性质(同底数幂的乘法、幂的乘方、积的乘方、同底数幂的除法),能用字母式子和文字语言正确地表述这些性质,并能运用它们熟练地进行运算。
2、思考对于数学的学习是最核心的,对做题更是如此。
数学是考你对知识点的运用,能够理解这些知识点,然后解题,通过解题巩固所学知识。
一开始不会解题,要忍住不去翻看答案,自己先思考。
3、在学习法则的过程中,不是简单地套用公式,而是除了理解法则的形成过程外,还需要知道每一个法则的具体适用情况,并会变式和引申。
在运用幂的运算法则进行计算时,一定要审清题,特别注意系数、符号和指数,其次要正确运用公式,看清底数和指数的变化,学会用转化的方法和整体的思想去解决问题。
快速幂算法
快速幂取余
所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余)。
在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。
应用的公式:
d=a b mod n=(…((((a mod n)*a)mod n)*a)mod n…*a)mod n {共b个a}
(a × b) mod c=( (a mod c) × b) mod c.
1.有三根杆子A,B,C。
A杆上有3N个(N>1)穿孔圆盘,共有N个不同的大小,每个尺寸都有三个完全相同的圆盘,盘的尺寸由下到上依次变小。
要求按下列规则将所有圆盘移至C 杆:
1.每次只能移动一个圆盘;
2.大盘不能叠在小盘上面。
费马小定理,积模分解公式,高效幂,快速幂模及米勒-拉宾检验
费马⼩定理,积模分解公式,⾼效幂,快速幂模及⽶勒-拉宾检验转载⾃好⽂章,整理收藏。
1.费马⼩定理:有N为任意正整数,P为素数,且N不能被P整除(显然N和P互质),则有:N^P%P=N(即:N的P次⽅除以P的余数是N) 或 (N^(P-1))%P=1互相变形:原式可化为:(N^P-N)%P=0(N*(N^(P-1)-1))%P=0所以,N*(N^(P-1)-1)是N和P的公倍数⼜因为 N与P互质,⽽互质数的最⼩公倍数为它们的乘积所以⼀定存在正整数M使得等式成⽴:N*(N^(P-1)-1)=M*N*P所以N^(P-1)-1=M*P因为M是整数所以(N^(P-1)-1)%P=0即:N^(P-1)%P=12.积模分解公式引理, 若:X%Z=0,则(X+Y)%Z=Y%Z 设有X、Y和Z三个正整数,则必有:(X*Y)%Z=((X%Z)*(Y%Z))%Z证明:1. 当X和Y都⽐Z⼤时,必有整数A和B使下⾯的等式成⽴: X=Z*I+A(1) Y=Z*J+B(2)除模运算的性质 将(1)和(2)代⼊(X*Y)modZ得: ((Z*I+A)(Z*J+B))%Z 所以 (Z*(Z*I*J+I*A+I*B)+A*B)%Z(3) 所以 Z*(Z*I*J+I*A+I*B)能被Z整除 概据引理,(3)式可化简为:(A*B)%Z ⼜因为:A=X%Z,B=Y%Z,代⼊上式,成为原式右边。
2. 当X⽐Z⼤⽽Y⽐Z⼩时: X=Z*I+A 代⼊(X*Y)%Z得: (Z*I*Y+A*Y)%Z 根据引理,转化得:(A*Y)%Z 因为A=X%Z,⼜因为Y=Y%Z,代⼊上式,即得到原式右边。
同理,当X⽐Z⼩⽽Y⽐Z⼤时,原式也成⽴。
3. 当X⽐Z⼩,且Y也⽐Z⼩时,X=X%Z,Y=Y%Z,所以原式成⽴。
3.快速乘⽅算法unsigned Power(unsigned n, unsigned p) //n^p{unsigned ans = 1;while (p > 1){if (( p & 1 )!=0) ans *= n;n *= n;p /= 2;}return n * ans;}4."蒙格马利”快速幂模算法__int64 Montgomery(__int64 n, __int64 p, __int64 m){ // 快速计算 (n ^ p) % m 的值,与power算法极类似__int64 r = n % m; // 这⾥的r可不能省__int64 k = 1;while (p > 1){if ((p & 1)!=0){k = (k * r) % m; // 直接取模}r = (r * r) % m; // 同上p /= 2;}return (r * k) % m; // 还是同上}蒙格马利极速版:unsigned Montgomery(unsigned n,unsigned p,unsigned m){ //快速计算(n^p)%m的值unsignedk=1;n%=m;while(p!=1){if(0!=(p&1))k=(k*n)%m;n=(n*n)%m;p>>=1;}return(n*k)%m;}5.素数判断根据费马⼩定理,对于两个互质的素数N和P,必有:N^(P-1)%P=1费马测试算法思路是这样的:对于N,从素数表中取出任意的素数对其进⾏费马测试,如果取了很多个素数,N仍未测试失败,那么则认为N是素数。
蒙哥马利算法原理
蒙哥马利算法原理蒙哥马利算法是一种用于在大整数运算中进行模幂运算的快速算法。
它在密码学领域被广泛应用于RSA算法、椭圆曲线密码算法等。
蒙哥马利算法的原理是利用模运算的特性,将大整数的幂运算转化为更简单的乘法运算,从而提高运算效率。
在介绍蒙哥马利算法之前,我们先来了解一下模运算的定义。
对于给定的两个正整数a和n,模运算的结果是a除以n所得的余数。
用数学符号表示为a mod n。
例如,对于整数17除以6的模运算,结果为17 mod 6 = 5。
模运算具有以下几个重要的性质:1. (a + b) mod n = (a mod n + b mod n) mod n2. (a - b) mod n = (a mod n - b mod n) mod n3. (a * b) mod n = (a mod n * b mod n) mod n蒙哥马利算法的核心思想是将大整数的幂运算转化为模运算的乘法运算。
具体步骤如下:1. 将底数a和指数b转化为二进制形式。
例如,对于a=3和b=11,它们的二进制形式分别为a=101、b=1011。
2. 通过反复平方和模运算,计算出a的各个幂次的模运算结果。
首先,计算出a mod n的结果,然后依次计算出a^2 mod n、a^4 mod n、a^8 mod n等,直到计算出a^b mod n的结果。
3. 根据指数b的二进制形式,利用模运算的性质计算出a^b mod n的结果。
例如,对于a^11 mod n,根据b=1011,我们可以根据模运算的性质得到以下计算式:a^11 mod n = (a^8 mod n * a^2 mod n * a^1 mod n) mod n。
蒙哥马利算法的优势在于它将大整数的幂运算转化为了一系列的模运算和乘法运算,避免了对大整数进行重复的乘法运算,从而大大提高了计算效率。
在实际应用中,蒙哥马利算法能够高效地对大质数进行加密和解密运算,保证了密码算法的安全性和可靠性。
几种方幂模快速算法的加法链一致性分析
山东工商学院 计算机科 学与技 术学院 , 山东 烟台 2 4 0 605
S h o o mp t r S i n e n e h o o y, h n o g I si t f Bu i e s a d T c n lg Ya t i S a d n 6 0 5 C i a c o l f Co u e ce c a d T c n l g S a d n n t u e o sn s n e h o o y, n a , h n o g 2 4 0 , h n t
to . m p tr En i e rn n piain . 0 0 4 ( 6 : 85 . inCo u e gn e i g a d Ap lc to s 2 a e p n n it n s h mo t r q e t u e a d i — o t at n sr c : d lr x o e tai i o t e s fe u n l y s d n t me c s p r i RS A, o e a t l o i m i n o wh s fs a g rt h s o e f t e o u e f RS su y, n o p e p t e c mp t t n o d lr e p n n i t n s mo t i o t n o h e f r n e h f c s s o A t d a d t s e d u h o u a i f mo u a x o e t i i o ao s mp ra t t t e p ro ma c
法、 分块算法 、 二进 制 自适应分组 查表法和最短加 法链 算法 , 出了加法链 的统一思想 , 为这几种 算法在 本质上都是加 法链 算 提 认
法 , 以后 的研 究 工 作 指 出 了方 向。 同 时指 出二 进 制 自适 应 分 组 查 表 法 可 以获 得 更 高的 整 体 效 率 , 仍 有进 一 步提 升 的 空 间 。 为 但
快速幂算法c语言版超详细
快速幂算法c语言版(超详细) 快速幂算法是一种在数值运算中常见的高效算法,它通过将问题分解为多个相同的子问题来实现快速求解。
在实现快速幂算法时,需要注意避免溢出和减少不必要的计算。
下面是一个详细的 C 语言版快速幂算法实现。
#include <stdio.h>long long fast_power(long long base, long long exponent, long long mod) {long long result = 1;while (exponent > 0) {if (exponent & 1) { // exponent 是奇数result = (result * base) % mod;}base = (base * base) % mod;exponent >>= 1; // 等价于 exponent = exponent / 2;}return result;}int main() {long long base, exponent, mod;printf("请输入底数,指数和模数: ");scanf("%lld %lld %lld", &base, &exponent, &mod);long long result = fast_power(base, exponent, mod);printf("快速幂算法的结果为: %lld\n", result);return 0;}在这个实现中,我们使用了一个 while 循环来迭代计算幂次。
在每次循环中,我们检查 exponent 的最后一位是否为 1(用于判断 exponent 是否为奇数)。
如果是,我们将 result 乘以 base 并取模。
然后,我们将 base 平方并取模,以便在下一次循环中继续计算。
幂运算常用的8个公式幂数口诀
幂运算常用的8个公式幂数口诀幂运算是数学中常用的运算之一,它用于表示一个数与自己相乘的运算。
在幂运算中,有许多常用的公式和口诀,掌握这些公式和口诀对于解题有很大的帮助。
下面我们一起来看看幂运算的常用公式和口诀。
一、公式部分1. 幂的乘法公式:对于相同的底数,幂的乘法公式为:a^m × a^n = a^(m+n)这个公式的意思是,如果要计算同一个底数的两个幂相乘的结果,只需要将底数保持不变,指数相加即可。
举个例子:2^3 × 2^4 = 2^(3+4) = 2^7 = 1282. 幂的除法公式:对于相同的底数,幂的除法公式为:a^m ÷ a^n = a^(m-n)这个公式的意思是,如果要计算同一个底数的两个幂相除的结果,只需要将底数保持不变,指数相减即可。
举个例子:10^5 ÷ 10^2 = 10^(5-2) = 10^3 = 10003. 幂的乘方公式:对于幂的幂,乘方公式为:(a^m)^n = a^(m×n)这个公式的意思是,如果要计算一个幂的幂的结果,只需要将底数保持不变,指数相乘即可。
举个例子:(2^3)^4 = 2^(3×4) = 2^12 = 40964. 幂的倒数公式:对于一个数的倒数的幂,倒数公式为:(1/a)^n = 1/(a^n)这个公式的意思是,如果要计算一个数的倒数的幂的结果,可以将其表示为原来数的幂的倒数。
举个例子:(1/2)^3 = 1/(2^3) = 1/8 = 0.125二、口诀部分1. 同底异幂相乘,指数相加求结果。
这个口诀的意思是,当计算同一个底数的两个不同幂相乘时,只需要将指数相加即可得到结果。
举个例子:2的3次方乘以2的4次方等于2的3加4次方,即2^3 × 2^4 = 2^(3+4) = 2^72. 同底异幂相除,指数相减求商。
这个口诀的意思是,当计算同一个底数的两个不同幂相除时,只需要将指数相减即可得到商。
很详细的快速幂算法
快速幂取模算法在网站上一直没有找到有关于快速幂算法的一个详细的描述和解释,这里,我给出快速幂算法的完整解释,用的是C 语言,不同语言的读者只好换个位啦,毕竟读C 的人较多~ 所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余)。
在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。
[有读者反映在讲快速幂部分时有点含糊,所以在这里对本文进行了修改,作了更详细的补充,争取让更多的读者一目了然]我们先从简单的例子入手:求c a b mod = 几。
算法1.首先直接地来设计这个算法:int ans = 1;for (int i = 1;i<=b;i++){ans = ans * a;}ans = ans % c;这个算法的时间复杂度体现在for 循环中,为O (b ).这个算法存在着明显的问题,如果a 和b 过大,很容易就会溢出。
那么,我们先来看看第一个改进方案:在讲这个方案之前,要先有这样一个公式: c c a c a b b m od )m od (m od =.这个公式大家在离散数学或者数论当中应该学过,不过这里为了方便大家的阅读,还是给出证明:引理1:cc b c a c de cde c dk te tkc ce kc d tc c ab ekc b e c b dtc a d c a cc b c a c ab mod )]mod ()mod [(mod mod ))((mod ))((mod mod mod mod )]mod ()mod [(mod )(:2⨯==+++=++=+=⇒=+=⇒=⨯=证明:公式上面公式为下面公式的引理,即积的取余等于取余的积的取余。
ca c c a c c c a cc a cc a c a b b b b b b mod mod ])mod [()(mod ])mod )mod [((mod ])mod [(mod )mod (mod ===由上面公式的迭代证明:公式:证明了以上的公式以后,我们可以先让a 关于c 取余,这样可以大大减少a 的大小, 于是不用思考的进行了改进:算法2:int ans = 1;a = a % c; //加上这一句for (int i = 1;i<=b;i++){ans = ans * a;}ans = ans % c;聪明的读者应该可以想到,既然某个因子取余之后相乘再取余保持余数不变,那么新算得的ans 也可以进行取余,所以得到比较良好的改进版本。
模幂运算密码学
模幂运算密码学【引言】密码学是现代信息安全领域的基石,而模幂运算作为密码学中的一种基本运算,其重要性和地位不言而喻。
本文将从定义、性质、应用、算法实现等方面对模幂运算进行详细介绍,以期帮助读者更好地理解和应用这一重要概念。
【模幂运算的定义和性质】模幂运算,顾名思义,就是将一个数模上一个另一个数的结果。
具体来说,设a、b为两个正整数,c为任意整数,则a的c次模幂运算可以表示为:a^c mod n。
在这里,n称为模数,满足0 < n < a。
模幂运算具有以下几个重要性质:1.结合律:对于任意正整数a、b、c,有(a^b)^c = a^(b*c)。
2.交换律:对于任意正整数a、b,有a^b = b^a。
3.幂运算的单位元:对于任意正整数a,有a^0 = 1。
4.幂运算的逆元:对于任意正整数a和满足0 < b < a的整数b,存在逆元a^(-b) mod n。
【模幂运算在密码学中的应用】模幂运算在密码学中的应用广泛,主要包括以下几个方面:1.加密:利用模幂运算的特性,可以将明文转换为密文,达到保密通信的目的。
2.数字签名:通过计算消息的模幂运算结果,可以实现对消息的数字签名,以确保消息的完整性和真实性。
3.公钥密码体制:利用模幂运算的逆元问题,可以实现公钥密码体制,如RSA算法。
【模幂运算的算法实现】在实际应用中,计算a的c次模幂运算通常采用以下两种算法:1.迭代算法:利用模乘运算和幂运算的结合律,将a的c次模幂运算转化为c-1次模乘运算和一次模幂运算的组合。
2.快速幂取模算法:利用二分思想,将c次模幂运算分解为两次模幂运算,再利用模乘运算和幂运算的性质进行计算。
【总结与展望】模幂运算在密码学中具有重要地位,其理论和实践研究不断取得突破。
尽管目前关于模幂运算的研究已经较为成熟,但仍有一些问题值得进一步探讨,如提高运算速度、降低存储需求等。
【原】模幂运算(ModularExponentiation)算法
【原】模幂运算(ModularExponentiation)算法模幂运算常常作为⼀些算法的中间求解步骤,算法的思路⼗分巧妙并且⾼效。
模幂运算的描述如下:已知b, e, m, 求c。
形如:其中,b<m (若b>m,可转换b为b%=m)算法⼀:最显⽽易见的办法就是先求幂,再取模。
例如,得到 c = 445。
注意到b=4为1位,e=13为2位,m=497为3位,c=445为3位,但是为8位。
这很可能造成溢出,或者因为⼤整数运算⽽缓慢。
可以采⽤快速求幂法求得,时间复杂度为 O(loge)1:int Power(int b, int e)2: {3:if (0 == b || 1 == b || 0 == e)4:return 1;5:if (1 == e)6:return b;7:int n = e>>1;8:int tmp = Power(b, n);9:if (0 == (e&1))10:return tmp*tmp;11:else12:return tmp*tmp*b;13: }算法⼆:称为Right to left binary method这⾥利⽤了等式:同时将e表⽰作⼆进制表⽰形式:所以可以表⽰为:因此所需求得的结果c为:算法实现如下:1:typedef __int64 BigInt;2:3://modular exponentiation4: BigInt modexp(BigInt b,BigInt e,BigInt m)5: {6: b%=m;7: BigInt result=1;8:while(e>0)9: {10:if( e&1 == 1 )11: result = (result*b)%m;12:// multiply in this bit's contribution while using modulus to keep result small13:// move to the next bit of the exponent, square (and mod) the base accordingly14: e >>= 1;15: b = (b*b)%m;16: }17:return result;18: }算法时间复杂度为O(loge),若算上⼤整数相乘则总复杂度为O(loge*logm*logm)。
大数模幂运算的快速算法
6. 输出 g;
算法 3 的实施过程中,令 M 为 2 的方幂,即 M=2k。经分析可看出,步骤 3 需要[logMx]*log2M= [log2x]次运算,步骤 4 中平均需要[logMx]*p
(ei!=0)=[ log2x ]*p(ei!=0)次模乘,这里 p(ei!=0)
k
=(1- 1 )为 ei 不为 0 的概率。如果将预计算中 M
2 常用的算法
2.1 二进制算法
模幂运算最常用也是最基本的算法,就是二
进制算法[5]。它先将指数用二进制表示,再采用
算法 1 描述的过程进行运算。
算法 1:
input:
a,
m,
x=∑
n −1 i=0
xi
为其二进制表示
output: g = ax(mod m)
pro: 1. 令 g = aX n−1 , I = n-2;
算法 5: input: a, m, x 的加法链为(u0, u1…us),长度 为 s,相关序列对为 w1…ws, wi = (i1, i2), output: g = ax(mod m) pro: 1.令 g0 = g; 2. i 从 1 递增到 s, 作如下操作: gi = gi1 * gi2; 3.输出 gs;
时所用的乘法次数最少,与一般的二进制算法相
比,运算次数减少了 15%。
附表 不同 k 值运算次数与占用资源的比较
k值
乘法次数 内存(按字节)
1
766
0
2
704
1028
3
666
3084
4
644
7196
5பைடு நூலகம்
640
15420
6
656
快速幂取模算法
快速幂取模算法1.⼤数模幂运算的缺陷:快速幂取模算法的引⼊是从⼤数的⼩数取模的朴素算法的局限性所提出的,在朴素的⽅法中我们计算⼀个数⽐如5^1003%31是⾮常消耗我们的计算资源的,在整个计算过程中最⿇烦的就是我们的5^1003这个过程缺点1:在我们在之后计算指数的过程中,计算的数字不都拿得增⼤,⾮常的占⽤我们的计算资源(主要是时间,还有空间)缺点2:我们计算的中间过程数字⼤的恐怖,我们现有的计算机是没有办法记录这么长的数据的,所以说我们必须要想⼀个更加⾼效的⽅法来解决这个问题2.快速幂的引⼊:我们⾸先从优化的过程开始⼀步⼀步优化我们的模幂算法1.朴素模幂运算过程:1#define ans=12for(int i=1;i<=b;i++)3 {4 ans*=a;5 }根据我们上⾯说的,这种算法是⾮常的⽆法容忍的,我们在计算的过程中出现的两个缺点在这⾥都有体现在这⾥我们如果要做优化的话,我肥就是每个过程中都加⼀次模运算,但是我们⾸先要记住模运算是⾮常的消耗内存资源的,在计算的次数⾮常的⼤的时候,我们是没有办法忍受这种时间耗费的2.快速幂引⼊:在讲解快速幂取模算法之前,我们先将⼏个必备的知识1.对于取模运算:1 (a*b)%c=(a%c)*(b%c)%c这个是成⽴的:也是我们实现快速幂的基础之后我们来看看快速幂的核⼼本质我通过离散课上的学习,将快速幂的本质差不多理解了⼀下,感觉还是很深刻的在这⾥,我们对指数动了⼀些⼿脚,核⼼思想在于将⼤数的幂运算拆解成了相对应的乘法运算,利⽤上⾯的式⼦,始终将我们的运算的数据量控制在c的范围以下,这样我们可以客服朴素的算法的缺点,我们将计算的数据量压缩了很⼤⼀部分,当指数⾮常⼤的时候这个优化是更加显著的,我们⽤Python来做⼀个实验来看看就知道我们优化的效率有多⾼了1from time import *2def orginal_algorithm(a,b,c): #a^b%c3 ans=14 a=a%c #预处理,防⽌出现a⽐c⼤的情况5for i in range(b):6 ans=(ans*a)%c7return ans89def quick_algorithm(a,b,c):10 a=a%c11 ans=112#这⾥我们不需要考虑b<0,因为分数没有取模运算13while b!=0:14if b&1:15 ans=(ans*a)%c16 b>>=117 a=(a*a)%c18return ans1920 time=clock()21 a=eval(input("底数:"))22 b=eval(input("指数:"))23 c=eval(input("模:"))24print("朴素算法结果%d"%(orginal_algorithm(a,b,c)))25print("朴素算法耗时:%f"%(clock()-time))26 time=clock()27print("快速幂算法结果%d"%(quick_algorithm(a,b,c)))28print("快速幂算法耗时:%f"%(clock()-time))我们现在知道了快速幂取模算法的强⼤了,我们现在来看核⼼原理:对于任何⼀个整数的模幂运算a^b%c对于b我们可以拆成⼆进制的形式b=b0+b1*2+b2*2^2+...+bn*2^n这⾥我们的b0对应的是b⼆进制的第⼀位那么我们的a^b运算就可以拆解成a^b0*a^b1*2*1...*a^(bn*2^n)对于b来说,⼆进制位不是0就是1,那么对于bx为0的项我们的计算结果是1就不⽤考虑了,我们真正想要的其实是b的⾮0⼆进制位那么假设除去了b的0的⼆进制位之后我们得到的式⼦是a^(bx*2^x)*...*a(bn*2^n)这⾥我们再应⽤我们⼀开始提到的公式,那么我们的a^b%c运算就可以转化为(a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)这样的话,我们就很接近快速幂的本质了(a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)我们会发现令A1=(a^(bx*2^x)%c)...An=(a^(bn*2^n)%c)这样的话,An始终是A(n-1)的平⽅倍(当然加进去了取模匀速那),依次递推我们可以得出以下的结论:1.如果b是偶数,我们可以记k = a2 mod c,那么求 (k)b/2 mod c就可以了。
C++快速幂运算
C++快速幂运算1.概念:快速幂运算也叫反复平⽅法。
顾名思义,算法就蕴含在名字中。
2.原理:假设要求x^n,如果n = 2^k,那么原题可以很轻松的表⽰为:x^n = ((x^2)^2)^2…。
这样只要做k次平⽅运算就能解决,时间复杂度就从O(n)下降到log(n)。
由上⾯的分析可知,只要幂运算的幂可以写成2^k的形式,就可以⽤上⾯的⽅法降低时间复杂度。
所以我们可以将任意的实数n改写有限个2^k的形式的相加。
例如:如图所⽰,x^22可以改写成x^16*x^4*x^2。
这样我们就可以分别对x^16和x^4以及x^2使⽤上述⽅法快速计算结果,最后只要相加就可以了。
3.代码实例:typedef long long ll;ll quick_pow(ll x,ll n,ll m){ll res = 1;while(n > 0){if(n & 1) res = res * x % m;x = x * x % m;n >>= 1;//相当于n=n/2.详情请参考位移运算符。
}return res;}4.另⼀种理解⽅法当b为偶数时,a^b可以转为a^2的b/2次⽅。
当b为奇数时,a^b可以转为a^2的b/2次⽅,再乘以a。
像这样不断递归下去,每次n都减半,于是可以在n(logn)时间内完成幂运算。
4.2代码实例:ll q_pow(ll x,ll n,ll m){if(n == 0) return 1;ll res = q_pow(x * x % m,n/2,m);if(n & 1) res = res * x % m;return res;}代码很精简,需要仔细看。
其中包含了模运算的相关知识,请⾃⾏百度。
数论——乘法逆元(快速幂求法)及模运算
数论——乘法逆元(快速幂求法)及模运算⼀、快速幂原理: 快速幂的原理⼗分简单。
a k=a2^0*a2^1*a2^2*...a2^x,其中k=20+21+22+ (2x) 这显然是正确的。
因为任何⼀个数都可以表⽰成⼆进制。
接下去利⽤位运算实现即可。
代码实现 模板题链接: 代码模板如下:时间复杂度O(logk)int qmi(int a,int k,int p){int res=1%p;while(k){if(k&1)res=(long long)res*a%p;a=(long long)a*a%p;k>>=1;}return res;} 值得⼀提的是,以上代码在过程中取模,是基于模运算的运算规则。
模运算有⼀些很好的性质,以下列举四条: (a + b) % p = (a % p + b % p) % p (a - b) % p = (a % p - b % p + p) % p (a * b) % p = (a % p * b % p) % p (a^b) % p = ((a % p)^b) % p⼆、快速幂求逆元乘法逆元的定义若整数 因为在模运算中,并没有除法的性质,即没有(a/b)%p≠((a%p)/(b%p))%p,⽽乘法逆元便可以帮助我们将其转化成乘法形式:a/b % m=a∗x % m。
由乘法逆元的定义我们可以推出如下结论:∵ a/b mod p = a * b-1 mod p = a/b * b * b-1 mod p∴ b * b-1≡ 1(mod p)费马⼩定理若p是⼀个质数,且整数a不是p的倍数(a与p互质),则有a p-1 ≡ 1(mod p)。
基于这个定理,我们就可以推出如下结论:∵ a p-1≡ 1(mod p)∴ a * a p-2≡ 1(mod p) 因此,结合乘法逆元的定义所得到的推论以及费马⼩定理,我们可以得到:a-1 = a p-2(mod p)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
幂模运算快速算法——滑动窗口算法
设e 的二进制表达式为:∑-==
10)2(k i i i e e ,其中}1,0{∈i e 。
那么,n X e mod 的幂模运算二进制算法如下:
输入:X ,e ,n
输出:n X C e
mod =
Step 1: 1=C
Step 2: for 1-=k i downto 0
Step 2.1: n C C C mod )*(=
Step 2.2: if 1=i e then n X C C mod )*(=
Step 3: return C
由二进制法的计算过程可知:当指数e 的二进制位为0时,会减少乘模的次数。
二进制法的直接推广是m 进制法,其基本思想是把指数分成r bits(即m 2log bits)的数据块,每次取指数e 的r bits 进行运算,从而使整个幂模运算的效率提高。
假定e 的每个比特是0或1的概率相同,则m 进制法一个数据块是全0的可能性为r -2,当r 增加时,数据块为全0的可能性会减少,因此在Step 2.2需做乘模的可能性增加;而当r 减小时,算法总的乘模次数也会增加。
滑动窗口技术提供了一种折衷,允许零数据块和非零数据块是变长的,目的是增加全0数据块的数量,从而使总的乘模次数减少。
具体方法是:把k bits 指数分解成z 个零窗口或非零窗口i F ,i F 长度为)(i F L 。
规定最大窗口长度为d ,即))(max(i F L d =,显然总窗口数z 可能不等于d k 。
d 的取值与模数的位长有关。
对单一窗口的幂模运算进行预处理,即预计算n X w mod ,其中
12,,7,5,3-=d w ,因为指数分解的原则使非零窗口的最低有效位必定为1,故w 为为奇数,从而使预处理次数减少了一半。
滑动窗口算法处理幂模运算的过程如下:
输入:X ,e ,n
输出:n X C e mod =
Step 1: 预计算。
Step 2: 将k bits 的指数e 分解成长度为)(i F L 的零窗口或非零窗口i F ,1,,2,1,0-=z i 。
Step 3: 1=C
Step 4: for 1-=z i downto 0
Step 4.1: n C C i F L mod )(2=
Step 4.2: if 0≠i F then n X C C i F mod )*(=
Step 5: return C
窗口的划分采用了从左至右扫描的变长滑动窗口技术,因为计算是从高位至低位进行的。
如果采用从
右至左扫描的变长滑动窗口技术虽然可以使零窗口的数量有所增加,但它存在一个增加开销的缺点——需要记录各窗口的大小,而从左至右扫描则恰好相反。