Java教程

扩展欧几里得算法

本文主要是介绍扩展欧几里得算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
  • 扩展欧几里得算法

  扩展欧几里得算法(英语: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     }

 

这篇关于扩展欧几里得算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!