SpringBoot+Vue實現第三方微博登入(一)
-
歐幾里得演算法
在數學中,輾轉相除法,又稱歐幾里得演算法(英語:Euclidean algorithm),是求最大公約數的演算法。兩個數的最大公約數就是能夠同時整除他們的最大正整數。輾轉相除法基於如下原理:兩個整數的最大公約數等於其中較小的數和兩數相除餘數的最大公約數。例如,252和105的最大公約數是21(252 = 21 x 12; 105 = 21 x 5 );因為252 − 105 = 21 × (12 − 5) = 147,所以147和105的最大公約數也是21。在這個過程中,較大的數縮小了,所以繼續進行同樣的計算可以不斷縮小這兩個數直至餘數為零。這時,所剩下的還沒有變成零的數就是兩數的最大公約數。由輾轉相除法也可以推出,兩數的最大公約數可以用兩數的整數倍相加來表示,如21 = 5 × 105 + (−2) × 252。這個重要的結論叫做裴蜀定理。
兩個數的最大公約數通常寫成GCD(a,b)。如果GCD(a,b)=1,則稱a和b互素。令g= GCD(a,b)。由於a和b都是g的整數倍,所以可以寫成a=mg、b=ng,並且不存在更大的整數G>g使等式成立。為了使g儘可能大,就要使a和b中所有公約數都提取出來歸入g中,所以自然數m和n一定互素,並且a和b的最大公約數g可以被a和b的所有其他公因數c整除。
三個數的最大公約數的定義和兩個數的相同,即是它們共有的素因數的積,它們或者也可以按下式計算:
GCD(a,b,c) = GCD(a, GCD(b,c)) = GCD(GCD(a,b),c) = GCD(GCD(a,c),b
所以,歐幾里得的輾轉相除法實際可以計算任意多整數的最大公約數。
-
輾轉相除法計算過程
輾轉相除法是一種遞迴演算法,每一步計算的輸出值就是下一步計算時的輸入值。設k表示步驟數(從0開始計數),演算法的計算過程如下:
每一步的輸入是都是前兩次計算的非負餘數rk−1和rk−2。因為每一步計算出的餘數都在不斷減小,所以,rk−1小於rk−2。在第k步中,演算法計算出滿足以下等式的商qk和餘數rk:
- rk−2=qkrk−1+rk
其中0 ≤rk<rk−1。也就是rk−2要不斷減去rk−1直到比rk−1小。
為求簡明,以下只說明如何求兩個非負整數a和b的最大公約數(負數的情況是簡單的)。在第一步計算時(k
- b=q1r0+r1
- r0=q2r1+r2
- r1=q3r2+r3
- …
如果有a<b,演算法的第一步實際上會把兩個數字交換,因為這時a除以b所得的商q0會等於0,餘數r0則等於a。然後,演算法的第二步便是把b除以a,再計算所得之商和餘數。所以,對於k≥ 0總有rk<rk−1,即運算的每一步中得出的餘數一定小於上一步計算的餘數。
由於每一步的餘數都在減小並且不為負數,必然存在第N步時rN等於0,使演算法終止,rN−1就是a和b的最大公約數。其中N不可能無窮大,因為在r0和0之間只有有限個自然數。
-
輾轉相除法計算機實現
Rust實現:
1 fn gcd(x: isize, y: isize) -> Option<isize> { 2 match (x,y) { 3 (0, 0) => None, 4 (a, 0) => Some(a.abs()), 5 (mut a, mut b) => { 6 while b != 0 { 7 let t = b; 8 b = a % b; 9 a = t; 10 } 11 12 Some(a.abs()) 13 }, 14 } 15 }
Rust測試程式碼:
1 #[test] 2 fn gcd_works() { 3 assert_eq!(gcd(3,4), Some(1)); 4 assert_eq!(gcd(10,5), Some(5)); 5 assert_eq!(gcd(1005,50), Some(5)); 6 assert_eq!(gcd(99977,777), Some(1)); 7 }