快速幂与大数乘积取模

快速幂:

计算a^n%p的值,怎么算呢?直接算固然可能溢出。咱们有一条引理:(a*b)%p=((a%p)*(b%p))%p.在这个引理上进行指数上的合并从而获得快速幂算法。html

具体地,有两种思路,一种是减少a值,以防溢出,一种是减少b值,加快计算。ios

怎么减少a值?a=a%p,就把a的值降到了p如下。对b呢,咱们发现,( a%p)*(a%p)=(a^2)%p,若是a^n次方n为偶数,a^(2m)%p = ((a^2)^m)%p,若是n为奇数,就先单独乘一个a,剩下的又是偶数了,这样n为偶数时就能够把n减少一半,从而下降了b的规模。算法

大数乘取余:

计算(a*b)%p怎么办?((a%p)*(b%p))%p仍是会溢出。post

下面用到一种思想,神奇与上面的快速幂有殊途同归之妙,把b当作二进制表示。spa

举个栗子:4*13%p,当作是4*1101(2)%p,其实表示的是4*(1*2^3+1*2^2+0*2^1+1*2^0)%p,那么咱们在计算的时候就把b当作二进制,若是二进制最后一位是1,就说明这一位应该乘a取余,为零说明这一位不用乘a,从低位开始不断将b的二进制式右移,同时将a乘以2,等同于把基数平方,缘由见上式。.net

代码:

 1 #include <iostream>
 2 using namespace std;
 3 long long q_mod(long long a,long long n,long long p)
 4 {
 5     a = a%p;
 6     //首先降a的规模
 7     long long sum = 1;//记录结果
 8     while(n)
 9     {
10         if(n&1)
11         {
12             sum = (sum*a)%p;//n为奇数时单独拿出来乘
13         }
14         a = (a*a)%p;//合并a降n的规模
15         n /= 2;
16     }
17     return sum;
18 }
19 long long q_mul(long long a,long long b,long long p)
20 {
21     long long sum = 0;
22     while(b)
23     {
24         if(b&1)//若是b的二进制末尾是零
25         {
26             (sum += a)%=p;//a要加上取余
27         }
28         (a <<= 1)%=p;//不断把a乘2至关于提升位数
29         b >>= 1;//把b右移
30     }
31     return sum;
32 }

能够发现二者很是的类似,差异在于结果变量的初值和计算中加号和乘号的区别。code

参考文章:

这几篇写得仍是比较清晰的:htm

六小聪,ACM算法:快速幂取模(详细),https://blog.csdn.net/dbc_121/article/details/77646508blog

ygeloutingyu,大数乘法取模运算(二进制),https://www.cnblogs.com/geloutingyu/p/5886626.htmlget

相关文章
相关标签/搜索