欧几里得算法(Euclidean Algorithm)
欧几里得算法(也称为辗转相除法)是一种查找两个正整数
a
a
a 和
b
b
b 的最大公约数的方法。
最大公约数(GCD - Greatest Common Divisor),另一个名字是HCF(Highest Common Factor)。
例子1:令
a
=
210
a=210
a=210,
b
=
45
b=45
b=45
210
‾
=
45
‾
∗
4
+
30
‾
45
‾
=
30
‾
∗
1
+
15
‾
30
‾
=
15
‾
∗
2
+
0
‾
\begin{align} \underline{210} &= \underline{45}*4+\underline{30}\\ \underline{45} &= \underline{30}*1+\underline{15}\\ \underline{30} &= \underline{15}*2+\underline{0} \end{align}
2104530=45∗4+30=30∗1+15=15∗2+0
其中,下划线数字可以认为是一些固定变量,而上述式子中的
4
4
4,
1
1
1,
2
2
2为这些固定变量的系数。
注意,当式子最后一个余数为0的时候,此时计算过程就结束了。
若采用编程语言进行表述,如下提供几个例子(注意输入时,一般假设
a
>
b
>
0
a>b>0
a>b>0):
(1)Python函数(请注意缩进关系):
def gcd(a, b):
while b:
a, b = b, a%b
return a
(2)C语言函数:
int hcf(int a, int b) {
if (b != 0) return hcf(b, a % b);
else return a;
}
另外,最小公倍数(LCM, Lowest/Least Common Multiple)与最大公约数紧密相关,如果已经计算出 a a a和 b b b两个整数的最大公约数记为 c c c,那么 l c m ( a , b ) = a / c ∗ b = a ∗ b / c lcm(a,b)=a/c*b=a*b/c lcm(a,b)=a/c∗b=a∗b/c。
扩展欧几里得算法(Extended Euclidean Algorithm)
除了计算
a
a
a和
b
b
b两个整数的最大公约数,此算法还能找到整数
x
x
x和
y
y
y(其中一个很可能是负数)。通常谈到最大公因子时, 我们都会提到一个非常基本的事实:给予二整数
a
a
a与
b
b
b, 必存在有整数
x
x
x与
y
y
y使得
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)。
扩展欧几里得算法还能够用于求解数论中乘法逆元(主要应用于密码学中)。
例子1续:令
a
=
210
a=210
a=210,
b
=
45
b=45
b=45
已知例子1中正向过程求得
g
c
d
(
210
,
45
)
=
15
gcd(210,45)=15
gcd(210,45)=15,以下提供逆向过程:
15
‾
=
30
‾
−
15
‾
=
30
‾
−
[
45
‾
−
30
‾
]
=
30
‾
∗
2
−
45
‾
=
[
210
‾
−
45
‾
∗
4
]
∗
2
−
45
‾
=
210
‾
∗
2
−
45
‾
∗
9
\begin{align} \underline{15} &= \underline{30}-\underline{15} \\ &= \underline{30} - [\underline{45}-\underline{30}]\\ &= \underline{30}*2 - \underline{45}\\ &= [\underline{210}-\underline{45}*4]*2 - \underline{45}\\ &= \underline{210}*2-\underline{45}*9\\ \end{align}
15=30−15=30−[45−30]=30∗2−45=[210−45∗4]∗2−45=210∗2−45∗9
此时,便得到
x
=
2
x=2
x=2,而
y
=
−
9
y=-9
y=−9。
在逆向过程中,首先提取一个最大公约数放在等式左边,接着通过正向过程中的等式代换
15
‾
\underline{15}
15,接着整理等式右侧;再代换
30
‾
\underline{30}
30,接着整理等式右侧;最后便得到形如
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)的式子。
例子2:令
a
=
7
a=7
a=7,
b
=
26
b=26
b=26,求取
x
=
a
−
1
mod
b
=
7
−
1
mod
26
x=a^{-1}\text{mod}\space b=7^{-1}\text{mod}\space 26
x=a−1mod b=7−1mod 26
本题意思:求取
7
7
7相对于模
26
26
26乘法运算的逆元(即乘法逆元)。
前提:
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1时,才存在乘法逆元,即
a
a
a与
b
b
b需要互为素数。
首先,提供正向过程(即应用辗转相除法):
26
‾
=
7
‾
∗
3
+
5
‾
7
‾
=
5
‾
∗
1
+
2
‾
5
‾
=
2
‾
∗
2
+
1
‾
\begin{align} \underline{26} &= \underline{7}*3+\underline{5}\\ \underline{7} &= \underline{5}*1+\underline{2}\\ \underline{5} &= \underline{2}*2+\underline{1} \end{align}
2675=7∗3+5=5∗1+2=2∗2+1
其中,下划线数字可以认为是一些固定变量,而上述式子中的
3
3
3,
1
1
1,
2
2
2为这些固定变量的系数。
注意,当式子最后一个余数为1的时候,此时计算过程就结束了(注意与例1的区别)。
接着,提供逆向过程(与例1续稍有不同):
1
‾
=
5
‾
−
2
‾
∗
2
=
5
‾
−
[
7
‾
−
5
‾
]
∗
2
=
5
‾
∗
3
−
7
‾
∗
2
=
[
26
‾
−
7
‾
∗
3
]
∗
3
−
7
‾
∗
2
=
26
‾
∗
3
−
7
‾
∗
11
=
26
‾
∗
3
+
7
‾
∗
15
\begin{align} \underline{1} &= \underline{5}-\underline{2}*2 \\ &= \underline{5} - [\underline{7}-\underline{5}]*2\\ &= \underline{5}*3 - \underline{7}*2\\ &= [\underline{26}-\underline{7}*3]*3 - \underline{7}*2\\ &= \underline{26}*3-\underline{7}*11\\ &= \underline{26}*3+\underline{7}*15\\ \end{align}
1=5−2∗2=5−[7−5]∗2=5∗3−7∗2=[26−7∗3]∗3−7∗2=26∗3−7∗11=26∗3+7∗15
此时,便得到
x
=
15
x=15
x=15,而
y
=
3
y=3
y=3。
在逆向过程中,首先将
1
‾
\underline{1}
1放在等式左边,接着通过正向过程中的等式代换
2
‾
\underline{2}
2,接着整理等式右侧;再代换
5
‾
\underline{5}
5,接着整理等式右侧;最后便得到形如
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)的式子。
另外,由于当前问题的乘法是模乘、加法是模加,所以最后得
−
11
mod
26
=
15
-11\text{mod}\space 26=15
−11mod 26=15。
另外,也可以看到
7
∗
15
mod
26
=
1
7*15\text{mod}\space 26=1
7∗15mod 26=1,即
7
7
7与
15
15
15相对于模
26
26
26乘法运算互为乘法逆元。
注意,乘法逆元属于初等数论(讨论整数的计算性质与特殊规律)中的知识,主要应用于密码学等技术(密码学中的数据必须是确定的数值,不能采用浮点数或小数进行表示,即使采用字符串表示小数,那也是一种整型或整数的表示形式)中。
若采用编程语言进行表述,如下提供几个例子:
(1)Python函数(请注意缩进关系):
def ext_euclid(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_euclid(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
(2)C语言函数:
int gcdEx(int a,int b,int*x,int*y)
{
if(b==0)
{
*x=1,*y=0 ;
return a ;
}
else
{
int r=gcdEx(b,a%b,x,y);
int t=*x ;
*x=*y ;
*y=t-a/b**y ;
return r ;
}
}