1.大數模冪運算的缺陷:
2.快速冪的引入:
1.朴素模冪運算過程:
1 #define ans=1 2 for(int i=1;i<=b;i++) 3 { 4 ans*=a; 5 }
2.快速冪引入:
1 from time import * 2 def orginal_algorithm(a,b,c): #a^b%c 3 ans=1 4 a=a%c #預處理,防止出現a比c大的情況 5 for i in range(b): 6 ans=(ans*a)%c 7 return ans 8 9 def quick_algorithm(a,b,c): 10 a=a%c 11 ans=1 12 #這里我們不需要考慮b<0,因為分數沒有取模運算 13 while b!=0: 14 if b&1: 15 ans=(ans*a)%c 16 b>>=1 17 a=(a*a)%c 18 return ans 19 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))
我們現在知道了快速冪取模算法的強大了,我們現在來看核心原理:
對於任何一個整數的模冪運算
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就可以了。
2.如果b是奇數,我們也可以記 ((k)b/2 mod c × a ) mod c 就可以了。
現在我們來考慮實現它:
迭代法:
1 int fast_pow(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)///奇數 8 { 9 ans=(ans*a)%c;///消除指數為奇數的影響 10 } 11 b>>=1; ///二進制的移位操作,不斷的遍歷b的二進制位 12 a=(a*a)%c; ///不斷的加倍 13 } 14 return ans; 15 }
遞歸法:
1 ll fast_pow(ll x,ll n,ll p) 2 { 3 ll temp; 4 x=x%p; 5 if(n==0)///終止條件 6 { 7 return 1; 8 } 9 temp=fast_pow((x*x)%p,n>>1,p); 10 if(n&1) 11 { 12 temp =temp*x%p;///消除指數為奇數的影響 13 } 14 return temp%p; 15 }
在這里還要進行幾點說明:
1.二進制的幾個運算符& 和 >> 。
&運算通常用於二進制取位操作,例如一個數 & 1 的結果就是取二進制的最末位。還可以判斷奇偶,x&1==0為偶,x&1==1為奇。
>>運算比較單純,二進制去掉最后一位,移位操作,不斷遍歷b的二進制位。
2. a=(a*a)%c這一步的作用是用來不斷的加倍,在先不看同余定理的情況下,a*a==a^2,下一步再乘,就是a^2*a^2==a^4,然后同理 a^4 * a4 =a^8 .........?是不是做到了
a-->a^2-->a^4-->a^8-->a^16-->a^32.......指數正是 2^i 啊,再看上面的例子,a¹¹ = a^(2^0) * a^(2^1) * a^(2^3),這三項是不是完美解決了,快速冪就是這樣。
