大数模幂运算快速算法
快速幂取模算法详解

快速幂取模算法详解转载https:///ltyqljhwcm/article/details/53043646 article>1.⼤数模幂运算的缺陷:快速幂取模算法的引⼊是从⼤数的⼩数取模的朴素算法的局限性所提出的,在朴素的⽅法中我们计算⼀个数⽐如5^1003%31是⾮常消耗我们的计算资源的,在整个计算过程中最⿇烦的就是我们的5^1003这个过程缺点1:在我们在之后计算指数的过程中,计算的数字不都拿得增⼤,⾮常的占⽤我们的计算资源(主要是时间,还有空间)缺点2:我们计算的中间过程数字⼤的恐怖,我们现有的计算机是没有办法记录这么长的数据的,所以说我们必须要想⼀个更加⾼效的⽅法来解决这个问题2.快速幂的引⼊:我们⾸先从优化的过程开始⼀步⼀步优化我们的模幂算法1.朴素模幂运算过程:1. #define ans=12. for(int i=1;i<=b;i++)3. {4. ans*=a;5. }根据我们上⾯说的,这种算法是⾮常的⽆法容忍的,我们在计算的过程中出现的两个缺点在这⾥都有体现在这⾥我们如果要做优化的话,我肥就是每个过程中都加⼀次模运算,但是我们⾸先要记住模运算是⾮常的消耗内存资源的,在计算的次数⾮常的⼤的时候,我们是没有办法忍受这种时间耗费的2.快速幂引⼊:在讲解快速幂取模算法之前,我们先将⼏个必备的知识1.对于取模运算:(a*b)%c=(a%c)*(b%c)%c这个是成⽴的:也是我们实现快速幂的基础之后我们来看看快速幂的核⼼本质我通过离散课上的学习,将快速幂的本质差不多理解了⼀下,感觉还是很深刻的在这⾥,我们对指数懂了⼀些⼿脚,核⼼思想在于将⼤数的幂运算拆解成了相对应的乘法运算,利⽤上⾯的式⼦,始终将我们的运算的数据量控制在c的范围以下,这样我们可以客服朴素的算法的缺点⼆,我们将计算的数据量压缩了很⼤⼀部分,当指数⾮常⼤的时候这个优化是更加显著的,我们⽤Python来做⼀个实验来看看就知道我们优化的效率有多⾼了1. from time import *2. def orginal_algorithm(a,b,c): #a^b%c3. ans=14. a=a%c #预处理,防⽌出现a⽐c⼤的情况5. for i in range(b):6. ans=(ans*a)%c7. return ans8.9. def quick_algorithm(a,b,c):10. a=a%c11. ans=112. #这⾥我们不需要考虑b<0,因为分数没有取模运算13. while b!=0:14. if b&1:15. ans=(ans*a)%c16. b>>=117. a=(a*a)%c18. return ans19.20. time=clock()21. a=eval(input(“底数:”))22. b=eval(input(“指数:”))23. c=eval(input(“模:”))24. print(“朴素算法结果%d”%(orginal_algorithm(a,b,c)))25. print(“朴素算法耗时:%f”%(clock()-time))26. time=clock()27. print(“快速幂算法结果%d”%(quick_algorithm(a,b,c)))28. print(“快速幂算法耗时:%f”%(clock()-time))实验结果:4. 朴素算法结果55. 朴素算法耗时:3.2899526. 快速幂算法结果57. 快速幂算法耗时:0.006706我们现在知道了快速幂取模算法的强⼤了,我们现在来看核⼼原理:1. 对于任何⼀个整数的模幂运算2. a^b%c3. 对于b我们可以拆成⼆进制的形式4. b=b0+b1*2+b2*2^2+…+bn*2^n5. 这⾥我们的b0对应的是b⼆进制的第⼀位6. 那么我们的a^b运算就可以拆解成7. a^b0*a^b1*2*…*a^(bn*2^n)8. 对于b来说,⼆进制位不是0就是1,那么对于bx为0的项我们的计算结果是1就不⽤考虑了,我们真正想要的其实是b的⾮0⼆进制位9.10. 那么假设除去了b的0的⼆进制位之后我们得到的式⼦是11. a^(bx*2^x)*…*a(bn*2^n)12. 这⾥我们再应⽤我们⼀开始提到的公式,那么我们的a^b%c运算就可以转化为13. (a^(bx*2^x)%c)*…*(a^(bn*2^n)%c)14. 这样的话,我们就很接近快速幂的本质了1. (a^(bx*2^x)%c)*…*(a^(bn*2^n)%c)2. 我们会发现令3. A1=(a^(bx*2^x)%c)4. …5. An=(a^(bn*2^n)%c)6. 这样的话,An始终是A(n-1)的平⽅倍(当然加进去了取模匀速那),依次递推现在,我们基本的内容都已经了解到了,现在我们来考虑实现它:1. int quick(int a,int b,int c)2. {3. int ans=1; //记录结果4. a=a%c; //预处理,使得a处于c的数据范围之下5. while(b!=0)6. {7. if(b&1) ans=(ans*a)%c; //如果b的⼆进制位不是0,那么我们的结果是要参与运算的8. b>>=1; //⼆进制的移位操作,相当于每次除以2,⽤⼆进制看,就是我们不断的遍历b的⼆进制位9. a=(a*a)%c; //不断的加倍10. }11. return ans;12. }现在,我们的快速幂已经讲完了我们来⼤致的推演⼀下快速幂取模算法的时间复杂度⾸先,我们会观察到,我们每次都是将b的规模缩⼩了2倍那么很显然,原本的朴素的时间复杂度是O(n)快速幂的时间复杂度就是O(logn)⽆限接近常熟的时间复杂度⽆疑逼朴素的时间复杂度优秀很多,在数据量越⼤的时候,者中优化效果越明显3.OJ例题POJ1995题意:快速幂版题1. #include“iostream”2. #include“cstdio”3. #include“cstring”4. #include“cstdlib”5.6. using namespace std;7.8. int ans=0;9. int a,b;10. int c;11.12. int quick(int a,int b,int c)13. {14. int ans=1;15. a=a%c;16. while(b!=0)17. {18. if(b&1) ans=(ans*a)%c;19. b>>=1;20. a=(a*a)%c;24.25. int main()26. {27. int for_;28. int t;29. scanf(“%d”,&t);30. while(t–)31. {32. ans=0;33. scanf(“%d%d”,&c,&for_);34. for(int i=1;i<=for_;i++)35. {36. scanf(“%d%d”,&a,&b);37. ans=(ans+quick(a,b,c))%c;38. }39. printf(“%d\n”,ans);40. }41. return 0;42. }</div></div></article>。
mod n大数幂乘的快速算法

mod n大数幂乘的快速算法
快速幂乘算法利用了指数的二进制表示方式来加速计算。
具体算法如下:
1. 初始化结果为1:result = 1
2. 将指数按二进制拆分为若干个二次幂:将指数n转换为二进制表示形式,例如n=13,二进制表示为1101,可以拆分为
2^0、2^2、2^3。
3. 从最低位开始遍历二进制位:
- 若当前位为1,则计算当前二次幂的乘积并累乘到结果中:result *= base^(2^i),其中base为底数,i为当前二进制位位置。
- 若当前位为0,则不做处理。
4. 返回结果。
例如,计算2^13的值:
拆分指数为2^0、2^2、2^3,可以得到2^13 = 2^0 * 2^2 * 2^3
= 2 * 4 * 8 = 128。
Python代码示例:
```python
def power(base, n):
result = 1
# 将指数n转换为二进制表示形式
binary_n = bin(n)[2:]
# 从最低位开始遍历二进制位
for i in range(len(binary_n)):
# 若当前位为1,则计算当前二次幂的乘积并累乘到结果中
if binary_n[i] == '1':
result *= base ** (2 ** i)
return result
# 测试
print(power(2, 13)) # 输出:128
```
快速幂乘算法的时间复杂度为O(logn),比普通的循环累乘要更高效。
该算法在计算大数的幂乘时特别有效,能够减少计算次数,提高计算速度。
幂的快速计算方法

幂的快速计算方法嘿,朋友们!今天咱来聊聊幂的快速计算方法,这可真是个超有用的本事呢!咱先从简单的例子说起哈。
比如 2 的 3 次方,那就是 2×2×2,等于8 呗。
可要是数字大一点,次方数高一点,那靠这样一个一个乘可得费老劲了。
咱可以找规律呀!就像玩游戏找通关秘籍一样。
比如说,2 的 4 次方,不就是 2 的 3 次方再乘个 2 嘛,那就是 8×2 等于 16 呀。
这就有点门道了吧!再比如 10 的几次方,这就更好玩啦。
10 的 2 次方就是 100,10 的3 次方就是 1000,你瞧,多简单明了!那 10 的4 次方不就是在 1000后面加个 0 嘛,这不是手到擒来嘛!还有哦,同底数幂相乘,底数不变指数相加,这可是个大宝贝呀!就像搭积木一样,把小的凑成大的。
比如说 2 的 3 次方乘 2 的 4 次方,那不就是 2 的 7 次方嘛。
那要是遇到除法呢?嘿,也有招!同底数幂相除,底数不变指数相减。
这就像分糖果一样,按比例来分。
咱再说说负数次方。
哎呀呀,这可别被吓到啦!负数次方就相当于求倒数的正数次方。
比如说 2 的负 3 次方,不就是 1 除以 2 的 3 次方嘛,算起来也不难呀。
想象一下,要是你掌握了这些方法,那算幂的时候不就跟玩儿似的,唰唰几下就出来了,多牛啊!其实呀,数学里好多东西就跟生活中的小窍门一样,找到了就特别好使。
幂的计算方法也是,一旦你掌握了,那在数学的世界里就能畅游啦!所以啊,大家可别小瞧了这幂的快速计算方法,它能让你的数学之路走得更顺畅呢!别再死记硬背啦,多找找规律,多玩玩这些数字游戏,你会发现数学的乐趣无穷大呀!就这么去试试吧,相信你会有大收获的!加油哦!。
快速模幂算法范文

快速模幂算法范文下面我们将详细介绍快速模幂算法的原理和步骤。
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。
大数模幂运算快速算法概要

有朋友问我的博文《素性测试》中的 Miller-Rabin 算法的大数模幂运算快速算法怎么理解,由于在《素性测试》中没有讲解算法原理,所以在此单独一个篇文章详细讲这个算法。
这是一个在密码学中比较重要的算法,在我的《素性测试》一文则是用于实现费马小定理。
首先我们先把问题简化一下,看看如何快速求 a^b.先看看我们熟知的两个数学公式:a^(2c = (a^c^2;a^(2c+1 = a*((a^c^2;我们就利用这两个数学公式来解决这个问题,比如 a=3,b=13时,我们把 b 写成二进制的形式 13(10=1101(2, 我们从低位到高位运算,每运算一位可以将 b 右移一位,上面的例子可以转化成 3^13 = 3^1 * 3^4 * 3^8, 结合上面的两个数学公式我们可以写出如下的代码:代码清单:[java]view plaincopy如上面的叙述叙述中可以看出快速 pow 算法的时间复杂度取决于 b 的二进制位数 ,而传统的一位一位累乘的 pow 算法的时间复杂度取决于 b 的大小 ,例如上述例子中,两种算法的运算次数分别为 4次,和 13次。
随着 b 的增大,效率上的差距是显然的。
下面进入我们的主题 ---大数模幂运算快速算法 (a^b % m要计算这个,我们首先还要知道一个数学公式:a^b % m = (...((a % m * a % m ......* a % m其中 a%m有 b 个下面我还用上面 b=13的例子,利用这个公式来证明下a^13 % m = ((a^8 % m * ((a^4 % m * ((a^1 % m证明:由 a^b % m = (...((a % m * a % m ......* a % m其中 a%m有 b 个得a^8 % m = (...((a % m * a % m ......* a % m其中 a%m有 8个a^4 % m = (...((a % m * a % m ......* a % m其中 a%m有 4个a^1 % m = (...((a % m * a % m ......* a % m 其中 a%m有 1个所以 ((a^8 % m * ((a^4 % m * ((a^1 % m = (...((a % m * a % m ......* a % m 其中a%m有 13个 = a^13 % m ;证毕。
幂运算常用的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、在学习法则的过程中,不是简单地套用公式,而是除了理解法则的形成过程外,还需要知道每一个法则的具体适用情况,并会变式和引申。
在运用幂的运算法则进行计算时,一定要审清题,特别注意系数、符号和指数,其次要正确运用公式,看清底数和指数的变化,学会用转化的方法和整体的思想去解决问题。
快速幂算法——精选推荐

快速幂算法快速幂算法1. 问题 -- 求2100的后三位数思路1 : 直接for循环求解 求出2的100次⽅再%1000即为后三位数 时间复杂度O(n)// base 底数 index 指数long long Pow(long long base, long long index) {int res = 1;for (int i = 0; i < index; i++) {res = res * base;}return res;}int main(){cout << Pow(2, 100) % 1000;return 0;}结果为0原因: 由于指数爆炸2的100次⽅会是⼀个⾮常⼤的数 我们所学的编程语⾔中没有数据类型能承受如此之⼤的数 所以产⽣了溢出解决办法 利⽤模运算法则2. “取模”运算的运算法则(a + b) % p = (a % p + b % p) % p (1)(a - b) % p = (a % p - b % p ) % p (2)(a * b) % p = (a % p * b % p) % p (3)(a^b) % p = ((a % p)^b) % p (4)我们只需要关注第3条法则 (a * b) % p = (a % p * b % p) % p推导过程:根据上⾯的推导过程 可以推导出(a * b * c) % p = (a % p * b % p * c % p) % p所以 (a * b * c * d * ......) = (a % p * b % p * c % p * d % p * ......) % p所以,借助这个法则,只需要在循环乘积的每⼀步都提前进⾏“取模”运算// base 底数 index 指数int Pow(int base, int index) {int res = 1;for (int i = 0; i < index; i++) {// 1 * 2 % 1000 * 2 % 1000 * ......res = res * base;res = res % 1000;}return res % 1000;}int main(){cout << Pow(2, 100);return 0;}结果 : 376 时间复杂度依旧为O(n) 所以当指数很⼤时运算需要很长时间 所以需要⽤到快速幂3.快速幂快速幂算法的核⼼思想是⼆分法: 每次都将指数/2 底数求平⽅平⽅310 = 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 需要10次运算将其对半分解310 = 3^10=(3 * 3) * (3 * 3) * (3 * 3) * (3 * 3) * (3 * 3) = (32)5 = 95此时需要 5次运算但此时指数为奇数⽆法整除2 所以将其分解为95 = 94 * 91对94继续进⾏分解95 = (9 * 9) * (9 * 9) * 9 = (92)2 * 9 = (81)2 * 9对812进⾏分解95 = (81 * 81)1 * 9 = 65611 * 9此时指数⼜为奇数但⽆法对指数进⾏压缩操作将上述流程转化为代码:long long Pow(long long base, long long index) {long long res = 1;while (index) {if (index % 2 != 0) { // 指数为奇数// 拆成A^1 和 A^(n - 1)res *= base;// 指数减⼀由于编程语⾔中默认向下取整所以index--可以不写//index--;}// 到这说明指数为偶数底数平⽅base *= base;// 指数减半index /= 2;}return res;}转化为上题代码long long Pow(long long base, long long index) {long long res = 1;while (index) {if (index % 2 != 0) {res = res * base % 1000;}base = (base * base) % 1000;index /= 2;}return res % 1000;}4.位运算优化判断⼀个数是奇数还是偶数可⽤位运算 如果⼀个数 a&1 == 0 则这个数为偶数 == 1 为奇数⼀个整数右移⼀位等于该数除以2a>>1 == a / 2long long Pow(long long base, long long index) {long long res = 1;while (index) {if (index&1) {res = res * base % 1000;index--;}base = (base * base) % 1000;index >>= 1;}return res % 1000;}。
幂模运算快速算法

幂模运算快速算法——滑动窗口算法设e 的二进制表达式为:∑-==10)2(k i i i e e ,其中}1,0{∈i e 。
那么,n X e mod 的幂模运算二进制算法如下:输入:X ,e ,n输出:n X C emod =Step 1: 1=CStep 2: for 1-=k i downto 0Step 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 。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
有朋友问我的博文《素性测试》中的Miller-Rabin算法的大数模幂运算快速算法怎么理解,由于在《素性测试》中没有讲解算法原理,所以在此单独一个篇文章详细讲这个算法。
这是一个在密码学中比较重要的算法,在我的《素性测试》一文则是用于实现费马小定理。
首先我们先把问题简化一下,看看如何快速求a^b.
先看看我们熟知的两个数学公式:
a^(2c) = (a^c)^2;
a^(2c+1) = a*((a^c)^2);
我们就利用这两个数学公式来解决这个问题,比如a=3,b=13时,我们把b写成二进制的形式13(10)=1101(2),我们从低位到高位运算,每运算一位可以将b右移一位,上面的例子可以转化成3^13 = 3^1 * 3^4 * 3^8,结合上面的两个数学公式我们可以写出如下的代码:
代码清单:
[java]view plain copy
如上面的叙述叙述中可以看出快速pow算法的时间复杂度取决于b的二进制位数,而传统的一位一位累乘的pow算法的时间复杂度取决于b的大小,例如上述例子中,两种算法的运算次数分别为4次,和13次。
随着b的增大,效率上的差距是显然的。
下面进入我们的主题---大数模幂运算快速算法(a^b % m)
要计算这个,我们首先还要知道一个数学公式:
a^b % m = (...((a % m) * a) % m) ......* a) % m其中a%m有b个
下面我还用上面b=13的例子,利用这个公式来证明下
a^13 % m = ((a^8) % m) * ((a^4) % m) * ((a^1) % m)
证明:
由a^b % m = (...((a % m) * a) % m) ......* a) % m其中a%m有b个得
a^8 % m = (...((a % m) * a) % m) ......* a) % m其中a%m有8个
a^4 % m = (...((a % m) * a) % m) ......* a) % m其中a%m有4个
a^1 % m = (...((a % m) * a) % m) ......* a) % m 其中a%m有1个
所以((a^8) % m) * ((a^4) % m) * ((a^1) % m) = (...((a % m) * a) % m) ......* a) % m 其中a%m有13个= a^13 % m ;
证毕。
由上面我们证明的公式和第一个pow的例子,容易写出代码如下:
代码清单:
[java]view plain copy
解释:当b=1101(2)时,从第1位开始result累乘,a = (a*a)%m加上循环可以看成表达式(a%m)^2 % m....因为(a%m)^2 % m = a^2 % m ,所以我们可以把a^13%m 看成((a^1) % m) ,((a^4) % m) ,((a^8) % m)的累乘,最后对m取模。
但累乘很容易造成溢出,所以我们可以把代码改成如下形式:
代码清单:
[java]view plain copy。