基本介紹
- 中文名:Stein算法
- 性質:算法
- 套用:計算兩個數最大公約數
- 針對:增加運算時間的缺陷
歐幾里德算法缺陷,算法思想,算法步驟,兩種算法的對比,C++/java 實現,Php實現,javascript實現,最佳化的C實現,Ruby實現,Pascal實現,
歐幾里德算法缺陷
一般實際套用中的整數很少會超過64位(當然現在已經允許128位了),對於這樣的整數,計算兩個數之間的模是很簡單的。對於字長為32位的平台,計算兩個不超過32位的整數的模,只需要一個指令周期,而計算64位以下的整數模,也不過幾個周期而已。但是對於更大的素數,這樣的計算過程就不得不由用戶來設計,為了計算兩個超過64位的整數的模,用戶也許不得不採用類似於多位數除法手算過程中的試商法,這個過程不但複雜,而且消耗了很多CPU時間。對於現代密碼算法,要求計算128位以上的素數的情況比比皆是,設計這樣的程式迫切希望能夠拋棄除法和取模。
算法思想
由J. Stein 1961年提出的Stein算法很好的解決了歐幾里德算法中的這個缺陷,Stein算法只有整數的移位和加減法,為了說明Stein算法的正確性,首先必須注意到以下結論:
gcd(a,a)=a,也就是一個數和其自身的公約數仍是其自身。
算法步驟
1、如果An=Bn,那么An(或Bn)*Cn是最大公約數,算法結束
2、如果An=0,Bn是最大公約數,算法結束
3、如果Bn=0,An是最大公約數,算法結束
4、設定A1=A、B1=B和C1=1
5、如果An和Bn都是偶數,則An+1=An/2,Bn+1=Bn/2,Cn+1=Cn*2(注意,乘2隻要把整數左移一位即可,除2隻要把整數右移一位即可)
6、如果An是偶數,Bn不是偶數,則An+1=An/2,Bn+1=Bn,Cn+1=Cn(很顯然啦,2不是奇數的約數)
7、如果Bn是偶數,An不是偶數,則Bn+1=Bn/2,An+1=An,Cn+1=Cn(很顯然啦,2不是奇數的約數)
8、如果An和Bn都不是偶數,則An+1=|An-Bn|/2,Bn+1=min(An,Bn),Cn+1=Cn
9、n加1,轉1
以前的算法有錯誤,因為cn根本就沒有用到。我編程的時候才發現。現在我已經修正了這個錯誤。
兩種算法的對比
C++/java 實現
#define CHECK(a) (!(1&(a)))//判斷是否被2整除#define CLEAN2(a) while(CHECK(a))a=a>>=1//移除非公因子的2#define BIGERA if(a<b)(t=a,a=b,b=t)//取較大的數為aint gcd(int a,int b){ int c_2=0,t; while((CHECK(a))&&(CHECK(b))){ a=a>>=1;b=b>>=1;c_2++; } CLEAN2(a); CLEAN2(b); BIGERA; while(a=((a-b)>>1)){ CLEAN2(a); BIGERA; } return b<<c_2;}//注意,由於中文百科會刪除空格,以上空格皆為全形空格//異或交換比中間量賦值慢//前一版在循環中有重複的判斷,在循環的結尾和絕對值處各判斷了一次ab的大小關係,所以效率受到影響//經過測試,比其他用遞歸的實現稍快,但是非常有限
Php實現
function steincore($a,$b) { if ($a == 0) {return $b;} if ($b == 0) {return $a;} while (($a & 1) == 0) { $a=$a>>1; } if ($a<$b) { $b=($b-$a)>>1; return steincore($b,$a); } else { $a=($a-$b)>>1; return steincore($a,$b); } }function stein($a,$b) { $c=0; while ((($a & 1)==0)&&(( $b & 1 )==0)) { $a=$a>>1; $b=$b>>1; $c=$c+1; } if (($a & 1) == 0) { $a=$a>>1; return steincore($a,$b)<<$c; } else { return steincore($b,$a)<<$c; }}//通過改善流程省去了低效的a,b交換,同時用while循環代替了過多的遞歸,以節約空間和時間。//疊代過程化為子過程以減少不必要的判斷//子過程中只有減法運算後的值可能為偶數所以只需要對$a判斷是否為偶數
javascript實現
function stein(a,b) { if (a==0) {return b;} if (b==0) {return a;} var c=0; while (((a & 1)==0)&&(( b & 1 )==0)) { a=a>>1; b=b>>1; c=c+1; } while ((a & 1)==0) { a=a>>1; } while ((b & 1)==0) { b=b>>1; } if (a<b) { b=(b-a)>>1; var r=stein(b,a)<<c; return r; } else { a=(a-b)>>1; var r=stein(a,b)<<c; return r; }}//基於php版修改而成
最佳化的C實現
int gcdcore(int a,int b) { if (a==0) return b; if (b==0) return a; while ((a & 0x1)==0) { a=a>>1; } if (a<b) { b=(b-a)>>1; return gcdcore(b,a); } else { a=(a-b)>>1; return gcdcore(a,b); }}int gcd(int a,int b) { int c=0; while (((a & 0x1)==0)&&(( b & 0x1 )==0)) { a=a>>1; b=b>>1; c++; } if ((a & 0x1) == 0) { a=a>>1; return gcdcore(a,b)<<c; } else { return gcdcore(b,a)<<c; }}
Ruby實現
def steincore(a,b) a === 0 ? (return b) : b === 0 ? (return a) : a=a>>1 while ((a&1)===0) a<b ? (return steincore((b-a)>>1,a)) : (return steincore((a-b)>>1,b))enddef GCD(a,b) c=0 a,b,c=a>>1,b>>1,c+1 while ((a & 1 === 0)&&( b & 1 === 0)) ((a & 1)===0) ? (a=steincore(a,b)) : (a=steincore(b,a)) return (a << c)end
Pascal實現
function stein(a,b :longint):longint;
Begin
if a < b then
begin
a:=a xor b;
b:=a xor b;
a:=a xor b;
end;
if b = 0 then exit(a);
If (a and 1 = 0) and (b and 1 = 0) then exit(stein(a shr 1,b shr 1) shl 1);
If (a and 1 = 0) then exit(stein(a shr 1,b));
If (b and 1 = 0) then exit(stein(a,b shr 1));
exit(stein((a+b)shr 1,(a-b)shr 1));
End;