扩展欧几里得算法

扩展欧几里得算法（Extended Euclidean algorithm）是欧几里得算法（又叫辗转相除法）的扩展。已知整数a、b，扩展欧几里得算法可以在求得a、b的最大公约数的同时，找到整数x、y（其中一个可能是负数），使它们满足贝祖等式$ax + by = \gcd(a, b)$。如果a是负数，可以把问题转化成$\left | a \right |(-x) + by = \gcd(|a|, b)$（$\left | a \right |$为a的绝对值），然后令$x'=(-x)$。

在欧几里得算法中，我们仅利用了每步带余除法所得的余数。扩展欧几里得算法还利用了带余除法所得的商，在辗转相除的同时也能得到贝祖等式中的x、y两个系数。以扩展欧几里得算法求得的系数是满足裴蜀等式的最简系数。

另外，扩展欧几里得算法是一种自验证算法，最后一步得到的$s_{i+1}$和$t_{i+1}$（$s_{i+1}$和$t_{i+1}$的含义见下文）乘以$\gcd(a,b)$后恰为$a$和$b$，可以用来验证计算结果是否正确。

扩展欧几里得算法可以用来计算模逆元，而计算模逆元是RSA加密算法中生成公钥、私钥的必要步骤。

## 算法和举例

在标准的欧几里得算法中，我们记欲求最大公约数的两个数为$a,b$，第$i$步带余除法得到的商为$q_i$，余数为$r_{i+1}$，则欧几里得算法可以写成如下形式：

$$\begin{align} r_0 & =a \\ r_1 & =b \\ & \,\,\,\vdots \\ r_{i+1} & =r_{i-1}-q_i r_i \quad \text {且} \quad 0\le r_{i+1} < |r_i| \\ & \,\,\, \vdots \end{align}$$

当某步得到的$r_{i+1}=0$时，计算结束。上一步得到的$r_i$即为$a,b$的最大公约数。

扩展欧几里得算法在$q_i$，$r_i$的基础上增加了两组序列，记作$s_i$和$t_i$，并令$s_0=1$，$s_1=0$，$t_0=0$，$t_1=1$，在欧几里得算法每步计算$r_{i+1}=r_{i-1}-q_i r_i$之外额外计算$s_{i+1}=s_{i-1}-q_i s_i$和$t_{i+1}=t_{i-1}-q_i t_i$，亦即：

$$\begin{align} r_0 & =a & r_1 & =b \\ s_0 & =1 & s_1 & =0 \\ t_0 & =0 & t_1 & =1 \\ & \,\,\,\vdots & & \,\,\,\vdots \\ r_{i+1} & =r_{i-1}-q_i r_i & \text {且} \quad 0 & \le r_{i+1} < |r_i| \\ s_{i+1} & =s_{i-1}-q_i s_i \\ t_{i+1} & =t_{i-1}-q_i t_i \\ & \,\,\, \vdots \end{align}$$

算法结束条件与欧几里得算法一致，也是$r_{i+1}=0$，此时所得的$s_i$和$t_i$即满足等式$\gcd(a,b)=r_i=as_i+bt_i$。

下表以$a=240$，$b=46$为例演示了扩展欧几里得算法。所得的最大公因数是$2$，所得贝祖等式为$\gcd(240,46)=2=-9*240+47*46$。同时还有自验证等式$|23|*2=46$和$|-120|*2=240$。

序号 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

这个过程也可以用初等变换表示。

$\begin{pmatrix}240 & 46\\1 & 0\\0 & 1\end{pmatrix} \rightarrow \begin{pmatrix}10 & 46\\1 & 0\\-5 & 1\end{pmatrix} \rightarrow \begin{pmatrix}10 & 6\\1 & -4\\-5 & 21\end{pmatrix} \rightarrow \begin{pmatrix}4 & 6\\5 & -4\\-26 & 21\end{pmatrix} \rightarrow \begin{pmatrix}4 & 2\\5 & -9\\-26 & 47\end{pmatrix}$

得到$-9\times 240+47\times 46=2$

## 证明

由于$0\le r_{i+1}<|r_i|$，$r_i$序列是一个递减序列，所以本算法可以在有限步内终止。又因为$r_{i+1}= r_{i-1} - r_i q_i$， $(r_{i-1}, r_i)$和$(r_{i}, r_{i+1})$的最大公约数是一样的，所以最终得到的$r_k$是$a$，$b$的最大公约数。

在欧几里得算法正确性的基础上，又对于$a=r_0$和$b=r_1$有等式$as_i+bt_i=r_i$成立（i = 0 或 1）。这一关系由下列递推式对所有$i>1$成立：

$$r_{i+1} = r_{i-1} - r_i q_i = (as_{i-1}+bt_{i-1}) - (as_i+bt_i)q_i = (as_{i-1}-as_iq_i) + (bt_{i-1}-bt_iq_i) = as_{i+1}+bt_{i+1}$$

因此$s_i$和$t_i$满足裴蜀等式，这就证明了扩展欧几里得算法的正确性。

## 实现

以下是扩展欧几里德算法的Python实现：

```python
def ext_euclid(a, b):
    old_s, s = 1, 0
    old_t, t = 0, 1
    old_r, r = a, b
    if b == 0:
        return 1, 0, a
    else:
        while(r!=0):
            q = old_r // r
            old_r, r = r, old_r-q*r
            old_s, s = s, old_s-q*s
            old_t, t = t, old_t-q*t
    return old_s, old_t, old_r
```

扩展欧几里得算法C++实现：

```c
#include <bits/stdc++.h>
using namespace std;

int ext_euc(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return a;
    }

    int d = ext_euc(b, a % b, y, x);
    y -= a / b * x;

    return d;
}

int main()
{
    int a, b, x, y;
    cin >> a >> b;

    ext_euc(a, b, x, y);
    cout << x << ' ' << y << endl;
    return 0;
}
```

## 外部链接

- Source for the form of the algorithm used to determine the multiplicative inverse in GF(2^8)