gcd/辗转相除法的证明
此文仅供蒟蒻参考,dalao请我也不记得是左上角还是右上角了。
前言
这不是小学奥数吗?
数学上来先打表,数论只会gcd。
上面几句话一直打击我学习数论的信心。
不仅只会gcd,连gcd都不会证明,可见我有多菜了。
直到受到某位dalao的指教,我终于证明了gcd。
dalao曰:”数论,数字之理论也。有术曰辗转相除,欲证此术,必先知反对称矣。”
那么问题来了,反对称是什么。
知识储备
下面内容很基础。对于我的证明方法来说,是必须要知道的。
1.整数具有大小(顺序)关系,用≤、≥、<、>、=来表示,其中≤具有反对称性,即:
a≤b a ≤ b 且 b≤a b ≤ a <=> a=b a = b (a∈Z,b∈Z) ( a ∈ Z , b ∈ Z )
可以说是非常基础的东西了,但是却是证明gcd的关键方法。
2.符号 | | 的含义:
若 (a∈Z,a≠0,q∈Z,b∈Z) ( a ∈ Z , a ≠ 0 , q ∈ Z , b ∈ Z ) ,则称 a a 为的约数(或 a a 整除),即 b/a b / a 的结果为整数(这里注意区分除和除以的区别),记作: a|b a | b ,符号 a|b a | b 蕴含条件 a≠0 a ≠ 0 。
3.整除的一个性质:
a|b a | b 且 a|c a | c => a|bx+cy a | b x + c y (x∈Z,y∈Z) ( x ∈ Z , y ∈ Z )
这个性质的证明:
由 a|b a | b 得 b=q1a b = q 1 a ,由 a|c a | c 得 c=q2a c = q 2 a ,则 bx+cy=q1xa+q2ya=a(q1x+q2y) b x + c y = q 1 x a + q 2 y a = a ( q 1 x + q 2 y ) 即 a|bx+cy a | b x + c y 。
4.余数的定义:
对于给定的 a∈Z,a≠0,b∈Z a ∈ Z , a ≠ 0 , b ∈ Z ,一定存在唯一的一对 q∈Z,0≤r<|a| q ∈ Z , 0 ≤ r < | a | 满足:
b=qa+r b = q a + r
我们称 q q 为的商,记作 q=[b/a] q = [ b / a ] (有时也记作 ⌊b/a⌋ ⌊ b / a ⌋ ⌊a⌋ ⌊ a ⌋ 表示对实数a向下取整,即取小于等于a的整数中最大的一个), r r 为的余数,记作 r=b−qa r = b − q a 。
扯了这么多乱七八糟的东西那么现在开始证明gcd。
gcd证明过程
用
gcd(n,m)
g
c
d
(
n
,
m
)
表示
n,m
n
,
m
的最大公约数,
证明:
gcd(n,m)=gcd(m,n mod m)
g
c
d
(
n
,
m
)
=
g
c
d
(
m
,
n
m
o
d
m
)
由
gcd
g
c
d
定义可得,(1)对于任意的
d|n
d
|
n
且
d|m
d
|
m
,都有
gcd(n,m)≥d
g
c
d
(
n
,
m
)
≥
d
。(2)
gcd(n,m)|n
g
c
d
(
n
,
m
)
|
n
且
gcd(n,m)|m
g
c
d
(
n
,
m
)
|
m
。
设:
易知:
由储备知识3得:
由储备知识4得:
所以:
由 a|n mod m a | n m o d m 及 a|m a | m
得:
即:
易知:
即:
由储备知识3易得:
因此:
即:
所以:
即:
以上就是gcd核心内容的证明。
上面其实是一个递归的过程,如何判断其何时终止呢?
我们知道除数不能为0,且0和任何的 a∈Z,a≠0 a ∈ Z , a ≠ 0 都有 gcd(a,0)=a g c d ( a , 0 ) = a ,因此当 m=0 m = 0 且 n≠0 n ≠ 0 时, gcd(n,m)=n g c d ( n , m ) = n ,这就是终止条件。
(据说 gcd(0,0)= g c d ( 0 , 0 ) = 无穷大)
编程实现
gcd是很容易编程实现的,明摆着就是一个裸的递归过程,因此用函数递归是最容易实现的。
递归实现:
C++版:
long long gcd(long long n, long long m)
{
if (m == 0) return n;
else return gcd(m, n % m);
}
C++简洁版:
long long gcd(long long n, long long m)
{
return m ? gcd(m, n % m) : n;
}
Pascal版:
function gcd(n, m:int64):int64;
begin
if m = 0 then exit(n)
else exit(gcd(m, n mod m));
end;
当然也有迭代实现(也就是循环实现)的,常数上可能稍微快一些。
迭代实现:
C++版:
long long gcd(long long n, long long m)
{
while (m)
{
n %= m;
swap(n, m);
}
return n;
}
Pascal版:
function gcd(n, m:int64):int64;
var t:int64;
begin
while m <> 0 do
begin
t:= m;
m:= n mod m;
n:= t;
end;
exit(n);
end;
终于把用了这么久的gcd证明出来了。