快速冪與大數乘積取模

快速冪:

計算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

相關文章
相關標籤/搜索