1、使用位元運算乘法。
把一個乘數變為2進位後,使用位元運算完成乘數的乘法。
- /*
- * 輸入:正整數k 和 正整數m
- * 輸出:k*m
- */
- __int64 km(__int64 k, __int64 m){
- __int64 x = k;
- int w = (int)floor(log(m) / log(2)) -1;
- __int64 e = 1 << w;
- for(int i=0; i<=w; i++){
- x <<= 1;
- if(m & e)
- x += k;
- e >>= 1;
- }
- return x;
- }
/*<br /> * 輸入:正整數k 和 正整數m<br /> * 輸出:k*m<br /> */<br />__int64 km(__int64 k, __int64 m){<br /> __int64 x = k;<br /> int w = (int)floor(log(m) / log(2)) -1;<br /> __int64 e = 1 << w;<br /> for(int i=0; i<=w; i++){<br /> x <<= 1;<br /> if(m & e)<br /> x += k;<br /> e >>= 1;<br /> }<br /> return x;<br />}
2、使用位元運算的乘方運算
指數變為2進位後,使用位元運算完成乘方運算。
虛擬碼:
C++實現
[cpp]
view plaincopyprint?
- /*
- * 輸入:正整數v mod m 和 g mod m
- * 輸出:g^v mod m
- */
- __int64 gvmm(__int64 g, __int64 v, __int64 m){
- int w = (int)floor(log(v) / log(2)) - 1;
- __int64 e = 1 << w;
- __int64 x = g;
- for(int i=0; i<=w; i++){
- x = (x * x) % m;
- if(v & e){
- x = (g * x) % m;
- }
- e >>= 1;
- }
- return x;
- }
/*<br /> * 輸入:正整數v mod m 和 g mod m<br /> * 輸出:g^v mod m<br /> */<br />__int64 gvmm(__int64 g, __int64 v, __int64 m){<br /> int w = (int)floor(log(v) / log(2)) - 1;<br /> __int64 e = 1 << w;<br /> __int64 x = g;<br /> for(int i=0; i<=w; i++){<br /> x = (x * x) % m;<br /> if(v & e){<br /> x = (g * x) % m;<br /> }<br /> e >>= 1;<br /> }<br /> return x;<br />}
乘方的測試:
使用普通演算法和位元運算演算法比較。
[cpp]
view plaincopyprint?
- #include <iostream>
- #include <math.h>
- #include <time.h>
- using namespace std;
-
- /*
- * 輸入:正整數v mod m 和 g mod m
- * 輸出:g^v mod m
- */
- __int64 gvmm(__int64 g, __int64 v, __int64 m){
- int w = (int)floor(log(v) / log(2)) - 1;
- __int64 e = 1 << w;
- __int64 x = g;
- for(int i=0; i<=w; i++){
- x = (x * x) % m;
- if(v & e){
- x = (g * x) % m;
- }
- e >>= 1;
- }
- return x;
- }
- /*
- * 驗證結果的普通演算法
- */
- int yanzheng(__int64 g, __int64 v, __int64 m){
- __int64 x = 1;
- for(int i=0; i<v; i++){
- x *= g;
- x %= m;
- }
- return x;
- }
-
- int main(){
- clock_t begin = clock();
- cout << yanzheng(23229,1892123, 23894) << endl;
- clock_t end = clock();
- double cost = (double)(end - begin) / CLOCKS_PER_SEC;
- printf("putong : %lf seconds\n", cost);
- begin = clock();
- cout << gvmm(23229,1892123, 23894) << endl;
- end = clock();
- cost = (double)(end - begin) / CLOCKS_PER_SEC;
- printf("weiyunsuan: %lf seconds\n", cost);
- system("pause");
- }
#include <iostream><br />#include <math.h><br />#include <time.h><br />using namespace std;</p><p>/*<br /> * 輸入:正整數v mod m 和 g mod m<br /> * 輸出:g^v mod m<br /> */<br />__int64 gvmm(__int64 g, __int64 v, __int64 m){<br /> int w = (int)floor(log(v) / log(2)) - 1;<br /> __int64 e = 1 << w;<br /> __int64 x = g;<br /> for(int i=0; i<=w; i++){<br /> x = (x * x) % m;<br /> if(v & e){<br /> x = (g * x) % m;<br /> }<br /> e >>= 1;<br /> }<br /> return x;<br />}<br />/*<br /> * 驗證結果的普通演算法<br /> */<br />int yanzheng(__int64 g, __int64 v, __int64 m){<br /> __int64 x = 1;<br /> for(int i=0; i<v; i++){<br /> x *= g;<br /> x %= m;<br /> }<br /> return x;<br />}</p><p>int main(){<br /> clock_t begin = clock();<br /> cout << yanzheng(23229,1892123, 23894) << endl;<br /> clock_t end = clock();<br /> double cost = (double)(end - begin) / CLOCKS_PER_SEC;<br /> printf("putong : %lf seconds\n", cost);<br /> begin = clock();<br /> cout << gvmm(23229,1892123, 23894) << endl;<br /> end = clock();<br /> cost = (double)(end - begin) / CLOCKS_PER_SEC;<br /> printf("weiyunsuan: %lf seconds\n", cost);<br /> system("pause");<br />}<br />
按照程式中給出的稍複雜的乘方運算,其效率分別為(多次測量後都差不多這個數量級)
21963
putong : 0.071000 seconds
21963
weiyunsuan: 0.001000 seconds
差不多普通演算法比位元運算演算法慢了50-70倍。