1.快速幂取模

http://www.cnblogs.com/yinger/archive/2011/06/08/2075043.html

快速幂取模就是在O(logn)内求出a^n mod b的值。算法的原理是ab mod c=(a mod c)(b mod c)mod c 

long exp_mod(long a,long n,long b)
{long t;if(n==0) return 1%b;if(n==1) return a%b;t=exp_mod(a,n/2,b);t=t*t%b;if((n&1)==1) t=t*a%b;return t;
}

2.大数取模运算Barrett reduction

https://blog.csdn.net/ykry35/article/details/79179285

Barrett reduction算法的证明和使用。

作者刚做完了课程设计作业,闲来无事写篇文章。

大数中的指数运算,需要对一个数进行取模,因为最大可能二进制下2048位的2048位次方,所以必须边做乘法边取模。

乘法使用快速幂,如果底数位数是x,指数位数是e,底数足够大的话,复杂度取决于模数,模数是m位的话,复杂度是O(m*m*e)。程序里,大数的存储是2的32次方进制的,这里的m*m要除以(32*32)。

取模运算,如果直接调用大数取模,因为除法是很慢的,所以效率很低。用Barrett reduction算法可以将除法转化为乘法和位运算,减法。

因为模数是任意的,所以不用蒙哥马利算法。

作业里只要求完成非负的大数运算,后面证明中默认大数都是非负的。

下面介绍Barrett reduction算法

求 x mod m

m的位数是k

使用条件: x位数不大于2*k。对同一个数反复取模。

使用方法(这里是非负数):

计算常量 mu=b^2k / m

取模时:

q1 = x / b^(k-1)

q2 = q1 * mu

q3 = q2 / b^(k+1)

r1 = x % b^(k+1)

r2 = (q3 * m) % b^(k+1)

r = r1 - r2

if ( r > m ) r -= m

return r

很多资料把mu=b^2k / m写成了mu=b^k / m,作者被坑了,很生气,决定放假写这么一个文章。另外,百度上基本看不到什么相关的证明。

证明:

[]表示取整,b是大数的进制

只需要一次除法预处理。

之后的除法和取模都是对进制b的若干次方进行的,所以位运算即可。

乘法时,因为最后结果是要取最后k+1位的,所以在乘的时候,可以直接把k+1位前面的丢弃,减少循环次数。作者是另外写了一个限制位数的乘法函数,效率提升了一些。

证明部分截图自word实验报告。

大数取模:一般取模+技巧取模+快速幂取模+欧拉函数(费马小定理)

https://blog.csdn.net/u011361880/article/details/77802742

一般取模运算(不推荐): 
(a^n)%m。 我们可以改写为(a^n)%m= ((a%m)^n)%m, 即循环n次。 
缺点:低效,循环了n次。

int exp_mod(int a,int n,int m){a = a%m;int temp = 1;while(n--){temp = temp * a;temp = temp % m;}return temp;
}

第一种,技巧取模: 
(a^n)%10 
当n非常大时,嗯,只能用字符串存n的时候。

简单分析一下, 
a%10. 有10种可能,(来源于室友“张博士”的逆天发现,明明可以靠脸吃饭,他偏偏要靠才华,明明可以快速幂取模,它偏要发现这种,出现大大大大数的)

a%10 = 0. 这个结果就不需要看了。0 
a%10 = 1. (1^n )%10会出现的可能数字:1 
a%10 = 2. (2^n )%10会出现的可能数字:2,4(=2*2), 8(=2*4),6(=2*8),继续循环,2, 4, 8, 6…..

a%10 = 3. (3^n )%10会出现的可能数字:3,9(=3*3),7(=3*9), 1(=3*7),继续循环,3,9,7,1…..

a%10 = 4. (4^n )%10会出现的可能数字:4,6(4*4) , 继续循环,4,6……

a%10 = 5. (5^n )%10会出现的可能数字:5 
a%10 = 6. (6^n )%10会出现的可能数字:6 
a%10 = 7. (7^n )%10会出现的可能数字:7, 9, 3, 1 继续循环, 
a%10 = 8. (8^n )%10会出现的可能数字:8, 4, 2, 6 继续循环, 
a%10 = 9. (9^n )%10会出现的可能数字:9, 1 继续循环,

重点是继续循环,发现,最大情况下,都是以4位数字循环,换句话说,(a^n)%10 和(a^(n+4))%10是相等的,当然,这里n不等于0. 如果这里看懂了,那这里差不多就ok了。

我们把n –> (n%4)+4. 这里加4的原因是为了防止n%4==0. ,并且我们没有考虑n==0的情况。这个单独处理一下。

OK 
如果n != 0. 
(a^n)%10 = (a^(n%4+4))%10 = ((a%10)^(n%4+4)) % 10

另外友情提示:对于n,如果是字符串存储,(十进制) 我们只需要取最后的2位数,用它代替n即可,因为999, 900肯定是可以被4整除的,我们只需要99即可,用99%4+4。 
如果是int 型或longlong。(二进制) (n & 11)按位“与”可以取出后2位,代替n%4,(注意不能代替n%4+4 . 加4一直需要),第3位是4,肯定可以被4整除。

第二种,快速幂取模: 
从一般取模的代码中,我们可以发现,每次都是重复的乘a。那么能否考虑,翻倍呢。看下面代码, 
这部分代码来源于 
http://www.cnblogs.com/yinger/archive/2011/06/08/2075043.html 
简单分析一下,类似于折半查找。

(a^n) %b

long exp_mod(long a,long n,long b)
{long t;if(n==0) return 1%b;if(n==1) return a%b;t=exp_mod(a,n/2,b);t=t*t%b;if((n&1)==1) t=t*a%b;return t;
}

这个代码就是一般的折半,递归,折半….。注意,(n&1) 按位“与 ”,如果是奇数,那么结果是1,否则结果是0.

来个惊喜一点的代码: 
来源于大神的回复 
:http://www.cnblogs.com/yinger/archive/2011/06/08/2075043.html

(a^n) %b

int exp_mod(int a,int b,int n){int r=1;while(b){if(b&1)r=(r*a)%n;a=(a*a)%n;b>>=1;       // b = b>>1;}return r;
}

主要思想还是折半。但是运用的非常巧妙,假设b是一个偶数,并且b/2.b/4,b/8.。。。。一直到2都是偶数,

OK,假设b == 16. a==2. 
b = 16,8,4,2,1 
我们发现,只有最后一次,b==1,时,我们进入了if语句, 
我们查看while循环里面,a的变化。(这里先不考虑模) 
b=16,进入while a = 2^2; 
b=8, a = 2^4; 
b=4, a = 2^8; 
b=2, a = 2^16 
b=1, ,进入if语句,r = a, 此时返回的是r。

假设b=18. 
b=18,进入while a = 2^2; 
b=9, 此时,进入了if语句。r=2^2. a = 2^4; 
b=4, a = 2^8; 
b=2, a = 2^16 
b=1, ,进入if语句,r = r*a = 2^2 * 2^16 , 此时返回的是r。

我们发现,在b=9时,我们用r保存了2^2. 为什么呢。反过来,从下往上看,我们要计算2^18次方。但是我们此时只知道2^8的结果,我们并不知道2^9是多少。因此,我们用了2个2^8. 此时,我们还是差了一个2^2. 
r保存的刚好是这个值。

当b是奇数时。b越小,说明离18越远,从下往上乘,我们一开始是差一个2(b=8和b=9差一个2),一直往上翻倍,即到了18,差2个2.即2^2。因此,r的值也需要越来越大。 (这里需要好好理解。) 
每碰到一次奇数,我们都会和原来的差一个2. 然后这个奇数距离18的距离越远。我们需要补回去的值就越大,即r的值。

重新举一个例子: 
b=22 进入while a = 2^2 
b=11 进入if,r = 2^2. a=2^4 ——>要补回2^2 
b=5 进入if, r=2^2 * 2^4. a = 2^8 ——> 要补回2^4 
b=2 a=2^16 
b=1,进入if, r = 2^2 * 2^4 * 2^16 
当b=11时,只知道2^5,用了两个,可以变成2^10. 
和11相差一个2.再到22即相差两个2. 
当b=5时,只知道2^2.用了两个。可以变成2^4,相差一个2. 再到10(11)时,翻倍,变成了2个。 
(10到11,在b=11那里已经补回来了),再到22,翻倍,变成2个。

第三种,欧拉函数: 
先介绍一个定义,互质:a和b互质,即a和b除了1以为,没有其他公约数。 
对正整数n,欧拉函数是小于n的数中与n 互质的数的数目, 
φ(8)=4,因为1,3,5,7均和8互质。

费马小定理: 
对于互质的整数a和n,有a^φ(n) ≡ 1 mod n 
即(a^φ(n)) % n = 1 %n = 1;

我们常常会见到。求(a^n)%1000000007, n>1000000007. 
因为m=1000000007是质数,毫无疑问,φ(m) = m-1 = 1000000006.

假设n = k * 1000000006 +r .其中r是余数, 
我们利用费马小定理降级处理。

(a^n)%1000000007 = (a^( k * 1000000006 +r ))%1000000007 
=(a^( k * 1000000006 ))%1000000007 * (a^r )%1000000007 
=1 * (a^r )%1000000007

直接把n变成了r。

大数取模运算,快速幂取模运算相关推荐

  1. C语言快速幂取模算法小结

    资料链接:http://www.jb51.net/article/54947.htm C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速幂,实际上是快 ...

  2. 【算法分析与设计】快速幂算法与快速幂取模算法

    文章目录 快速幂算法 算法分析 算法实现 位运算优化 BigInteger支持 快速幂取模算法 算法优点 算法推导 算法实现 BigInteger支持 本文完整代码实现(Java语言描述) 快速幂算法 ...

  3. CodeForces Round #191 (327C) - Magic Five 等比数列求和的快速幂取模

    很久以前做过此类问题..就因为太久了..这题想了很久想不出..卡在推出等比的求和公式,有除法运算,无法快速幂取模... 看到了 http://blog.csdn.net/yangshuolll/art ...

  4. A hard puzzle(HDU1097)(快速幂取模)

    题目链接: HDU1097 题面: 翻译: 问题描述 lcy给了feng5166,lwg,JGShining和Ignatius一个难题:给了a和b,如何知道a^b.每个人都反对这个BT问题,所以lcy ...

  5. 快速幂取模——Pupu(HDU 3003)

    题目: 由题目推出计算公式: ans = (2^(n-1) + 1) % n 因为n取值很大,所以需要用到快速幂取模: int multi(int a,int b) { int ret; ret=1; ...

  6. c语言的幂乘积表达式,POJ 1845 Sumdiv [素数分解 快速幂取模 二分求和等比数列]

    大致题意: 求A^B的所有约数(即因子)之和,并对其取模 9901再输出. 解题基础: 1) 整数的唯一分解定理: 任意正整数都有且只有一种方式写出其素因子的乘积表达式. ,其中 为素数 2) 约数和 ...

  7. 数学--数论--HDU 4675 GCD of Sequence(莫比乌斯反演+卢卡斯定理求组合数+乘法逆元+快速幂取模)

    先放知识点: 莫比乌斯反演 卢卡斯定理求组合数 乘法逆元 快速幂取模 GCD of Sequence Alice is playing a game with Bob. Alice shows N i ...

  8. 【快速幂取模】NOI 7833:幂的末尾

    NOI 7833:幂的末尾     点击打开链接 总时间限制: 1000ms 内存限制: 65536kB 描述 幂ab的末3位数是多少? 输入 两个正整数a,b.1 <= a <= 100 ...

  9. 【算法】求n的m次方(快速幂取模)

    题目 求n的m次方,n,m均为自然数. 解析 看似简单的题目,但是要想写的高效还不是那么容易想出来. 实现 unsigned int power(unsigned int a, unsigned in ...

最新文章

  1. Android ListView (多个adapter 说明)
  2. Android的Adapter用法总结
  3. 利用python下载网页到本地(python3)
  4. 自定义服务器控件ImageButton
  5. Codeforces Round #564 (Div. 2)A
  6. xtrabackup备份mysql5.7_【 xtrabackup】CentOS7.x上基于 MySQL 5.7.x的XtraBackup 安装与备份还原...
  7. php打png图片水印颜色失真,ThinkPHP水印功能实现修复PNG透明水印并增加JPEG图片质量可调整...
  8. 结果期待3年多的看图软件
  9. 为什么Redux需要reducer成为“纯函数”
  10. Unity手游之路三 基于Unity+Java的聊天室源码
  11. 2020 从新开始:你应该知道的Oracle认证新变化
  12. 入门命令23-更换CMD窗口的颜色:color
  13. 微信公众号支付开发全过程
  14. php网上订餐,php网上订餐系统
  15. 安卓机自动肝手游脚本
  16. Java学习——类和对象(上)
  17. C语言 编程实现简单的计算器功能
  18. DTC设置控制$85服务
  19. Premiere导出视频音画不同步的解决方案
  20. xp访问win10计算机名,win10共享打印机给xp凭证问题_xp连接win10打印机凭证不足解决方法...

热门文章

  1. [PTA]习题4-2 求幂级数展开的部分和
  2. 这才是字节跳动(今日头条)面试?
  3. 2019年web前端就业前景和工资待遇
  4. 华为机试:DNA序列
  5. css html制做王者荣耀网站,css3配合js做王者荣耀3D旋转购买英雄效果以及源码展示...
  6. 5个帮你改掉坏习惯的方法
  7. Hadoop YARN配置参数剖析(4)—Fair Scheduler相关参数
  8. 【RoCE】Flow Control
  9. 院校情报福州大学计算机考研分析,福州大学情报学考研
  10. sql语句 四表联查