擴展歐幾里得算法


  • 擴展歐幾里得算法

  擴展歐幾里得算法(英語: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

     r= b

      .......

    ri+1 = ri-1 - qri   且 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 - qri 之外額外計算

si+1 = si-1 - qsi 和 ti+1 = ti-1 - qti,亦即:

     r0 = a      r1 = b

     s0 = 1      s1 = 0

     t0 = 0      t1 = 1

       ......                    ......

   ri+1 = ri-1 - qri   且 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     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM