js 基本語法
-
擴充套件歐幾里得演算法
擴充套件歐幾里得演算法(英語:Extended Euclidean algorithm)是歐幾里得演算法(又叫輾轉相除法)的擴充套件。已知整數a、b,擴充套件歐幾里得演算法可以在求得a、b的最大公約數的同時,能找到整數x、y(其中一個很可能是負數),使它們滿足貝祖等式:
ax + by = gcd(a, b)
如果a是負數,可以把問題轉化成:
|a|(-x) + by = gcd(|a|, x) (|a|為a的絕對值,然後令x' = (-x)。
通常談到最大公約數時,我們都會提到一個非常基本的事實(貝祖等式給定):給定二個整數a、b,必存在整數x、y使得ax + by = gcd(a,b)
眾所周知,已知兩個數a和b,對它們進行輾轉相除,可得它們的最大公約數。不過,在歐幾里得演算法中,我們僅僅利用了每步帶餘除法所得的餘數。擴充套件歐幾里得演算法還利用了帶餘除法所得的商,在輾轉相除的同時也能得到貝祖等式中的x、y兩個係數。以擴充套件歐幾里得演算法求得的係數是滿足裴蜀等式的最簡係數。
另外,擴充套件歐幾里得演算法是一種自驗證演算法,最後一步得到的si+1和ti+1(si+1和ti+1的含義如下)乘以gcd(a,b)之後恰好是a和b,可以用來驗證計算結果是否正確。
擴充套件歐幾里得演算法可以用來計算模反元素(也叫模逆元),求出模反元素是RSA加密演算法中獲得所需公鑰、私鑰的必要步驟。
-
演算法和舉例
在標準的歐幾里得演算法中,我們記欲求最大公約數的兩個數為a和b,第i步帶餘除法得到的商為qi,餘數為ri+1,則歐幾里得演算法可以寫成如下形式:
r0 = a
r1= b
.......
ri+1 = ri-1 - qiri 且 0 ≤ ri+1 < |ri|
......
當某步得到的 ri+1= 0 時,計算結束。上一步得到的ri即為a,b的最大公約數。
擴充套件歐幾里得演算法在qi,ri的基礎上增加了兩組序列,記作si和ti,並s0 = 1, s1 = 0, t0 = 0, t1 = 1,在歐幾里得演算法每步計算ri+1= ri-1
si+1 = si-1 - qisi和 ti+1 = ti-1 - qiti,亦即:
r0= a r1= b
s0 = 1 s1 = 0
t0= 0 t1 = 1
...... ......
ri+1= ri-1- qiri 且 0 ≤ ri+1< |ri|
si+1= si-1- qi si
ti+1= ti-1- qi ti
......
演算法結束條件與歐幾里得演算法一致,也是ri+1= 0,此時所得的si和ti即滿足等式gcd(a, b) = ri = asi + bti。
下表以a = 240,b = 46為例演示了擴充套件歐幾里得演算法:
序號i | 商qi−1 | 餘數ri | si | ti |
0 | 240 | 1 | 0 | |
1 | 46 | 0 | 1 | |
2 | 240÷46=5 | 240−5×46=10 | 1−5×0=1 | 0 −5× 1 = −5 |
3 | 46÷10=4 | 46−4×10=6 | 0−4×1=−4 | 1 −4× −5 = 21 |
4 | 10÷6=1 | 10−1×6=4 | 1−1×−4=5 | −5 −1× 21 = −26 |
5 | 6÷4=1 | 6−1×4=2 | −4−1×5=−9 | 21 −1× −26 =47 |
6 | 4÷2=2 | 4−2×2=0 | 5−2×−9=23 | −26 −2× 47 =−120 |
所得的最大公因數是2,所得貝祖等式為gcd(240, 46) = 2 = -9* 240 + 47 * 46。同時還有自驗證等式|23| * 2 = 46 和 |-120| * 2 = 240。
-
擴充套件歐幾里得演算法和模逆元實現
以下是擴充套件歐幾里德演算法的Rust實現:
1 pub fn extend_euclidean(a: isize,b: isize)->(isize,isize,isize){ 2 if b == 0{ 3 return ( 1,0,a); 4 }else { 5 let (mut old_r,mut r) = (a,b); 6 let (mut old_s,mut s) = (1,0); 7 let (mut old_t,mut t) = (0,1); 8 while r != 0{ 9 let q = old_r/r; 10 11 let temp = old_r; 12 old_r = r; 13 r = temp - q*r; 14 15 let temp = old_s; 16 old_s = s; 17 s = temp - q*s; 18 19 let temp = old_t; 20 old_t = t; 21 t = temp - q*t; 22 } 23 (old_s,old_t,old_r) 24 } 26 }
模逆元Rust實現:
1 pub fn mod_inverse(a: isize,n:isize)->Option<isize>{ 2 let (s,_t,gcd) = extend_euclidean(a,n); 3 if gcd != 1{ 4 return None; 5 } 6 if s > 0{ 7 Some(s) 8 }else { 9 Some(s+n) 10 } 11 }
擴充套件歐幾里得演算法以及模逆元測試程式碼:
1 #[test] 2 fn ext_gcd_test(){ 3 let a = 7; 4 let n = 977; 5 let (s,t,gcd) = extend_euclidean(a,n); 6 assert_eq!((-279,2,1),extend_euclidean(7,977)); 7 8 assert_eq!(mod_inverse(47,977),Some(686)); 9 10 }