非递归的扩展欧几里得算法

$\DeclareMathOperator{\extgcd}{extgcd}$

作者按:写这篇随笔是为了解释 tourist 的逆元模板

template <typename T>
T inverse(T a, T m) {
    T u = 0, v = 1;
    while (a != 0) {
        T t = m / a;
        m -= t * a; swap(a, m);
        u -= t * v; swap(u, v);
    }
    assert(m == 1);
    return u; // 注意:u 可能为负数
}

扩展欧几里德算法是求不定方程 $ax + by = \gcd(a,b)$ 的一组解 $(x, y)$;若 $a$ 和 $b$ 互素,$x$ 即 $a$ 在模 $b$ 下的逆元。常见的求逆元算法实现如下

int extgcd(int a, int b, int& x, int& y) {
  int d = a;
  if (b != 0) {
    d = extgcd(b, a % b, y, x);
    y -= (a / b) * x;
  } else {
    x = 1; y = 0;
  }
  return d;
}

int mod_inverse(int a, int m) {
    int x, int y;
    extgcd(a, m, x, y);
    return (m + x % m) % m;
}

求 $a$ 在模 $m$ 下的逆元时,往往事先已经知道 $\gcd(a, m) = 1$;此外,对于方程 $ax + my = 1$,我们并不需要把 $x, y$ 求出来,而只需要求出 $x$,也就是说我们不必关心 $y$ 是多少。退一步讲,即便我们需要求出 $y$,求出 $x$ 之后再做一次除法即可。相比于 tourist 的实现,上述代码是不够高效的,一则含有冗余计算,二则采用递归实现。下面分析 tourist 的非递归实现之原理。

$r_0 = r_1 q_2 + r_ 2 $
$r_1 = r_2 q_3 + r_3$
$r_2 = r_3 q_4 + r_4$
$\vdots$
$r_{i - 2} = r_{i - 1} q_i + r_i $
$\vdots$
$r_{n - 2} = r_{n - 1} q_n + r_{n}$
$r_{n} = 0$

我们有

$\gcd(r_0, r_1) = \gcd(r_1, r_2) = \dots = \gcd(r_{n - 2}, r_{n - 1}) = \gcd(r_{n - 1}, r_{n}) = r_{n - 1}$

令 $r_i = s_i a + t_i b$,
又 $r_i = r_{i - 2} - r_{i - 1} q_i $
故有
\begin{aligned}
r_i &= s_{i - 2} a + t_{i - 2} b - (s_{i - 1} a + t_{i - 1} b) q_i \\
&= (s_{i - 2} - q_i s_{i - 1}) a + (t_{i - 2} - t_{i - 1} q_i) b
\end{aligned}

注意到 $s_i$ 的递推式中未出现 $t$,而我们只要求出 $s_{n - 1}$ 即可,因此可以不管 $t$,只维护 $s$ 。

令 $r_0 = a, r_1 = m$,即 $s_0 = 1, s_1 = 0$;且令 $q_2 = 0$,即令 $r_2 = a$ 。

每次循环结束之后,最新的 $r$ 保存在变量 a 中。在循环开始之前最新的 $r$ 是 $r_2$ 。

通过上述分析可以知道当循环结束时,即 a 的值变为 $r_n = 0$ 时,m 的值是 $r_{n - 1} = \gcd(a, m)$ 。

我们看到两种实现所依据的都是欧几里得算法,下面来讨论扩展欧几里得算法算出的 $ax + by = \gcd(a,b)$ 的解的大小

用归纳法可以证明,若 $ab\ne 0$,则 $|x| \le b$ 且 $|y|\le a$ 。

在 $ b = 0$ 的前一步,即 $a \% b = 0$ 时有 $x = 0$ 且 $y = 1$,结论显然成立。假设调用 extgcd(b, a % b, y', x') 后有 $|x'| \le b$ 且 $|y'| \le a \% b$ 。在 extgcd(a, b, x, y) 中 $x = x', y = y' - (a / b) x '$,所以有如下不等式成立
$|x| = |x'| \le b, |y| = |y' - (a / b)x'| \le |y'| + (a /b )|x'| \le a \% b + (a / b) \times b = a$

References

https://brilliant.org/wiki/extended-euclidean-algorithm/#extended-euclidean-algorithm

猜你喜欢

转载自www.cnblogs.com/Patt/p/11638063.html