从欧几里得开始(四)

从欧几里得开始(四)

这次从接着上次的故事继续吧,欧几里得算法求解最大公约数;

上面几节介绍了一种计算出,一个自然数N所有约数的算法,耗时不长,也不短,

大概在\(Nln(\lfloor \frac{N}{2} \rfloor+1)\)这个量级。

比如说对于N=10000这个大小的数,找出所有的约数,需要\(10000ln(5000+1)=85173.93\)差不多这个数字的比较次数,就是计算机需要执行比较的次数在这个量级,进一步来说如果一次比较耗费几次是cpu的时钟,比如5次或者更多。那么对于一个在1GHz计算能力的cpu来说,

1Ghz代表,每秒运算时钟可以跳\(1\times 10^9\)次,那么每秒可以执行\(\frac{1\times 10^9}{{5}}=2\times10^8\)次比较运算。

这样,用这块cpu来跑,那么只是在比较上耗费的时间就可以估算出来:

\(\frac {85173.93}{2\times 10^8}\approx 4.25\times10^{-4}秒=0.425毫秒\),可能这个数字不准,因为,这里没有考虑读取除了比较之外的时间,也对于比较运算在cpu上的实现在5个时钟周期也是一个假设,但是,在这里提出,这样的问题是说明,计算一个程序的耗时是可以按照这一套方法来的,就是统计出在这个程序中有哪些运算,每个运算在cpu那里可以用几个时钟周期实现,剩下的问题就是单位之间的转换。

公约数,我们理解的是这是两个自然数的公有的约数,所以公约数的一个性质是如果一个数\(a\)是自然数\(N_1\)和自然数\(N_2的公约数,\)那么有结论:数a是\(N_1\)的约数,数a是\(N_2\)的约数。这是我们对于公约数最直接的理解,约数的重叠部分。那么,很自然地就有一种做法去求解最大公约数:

1,先找出自然数\(N_1\)的所有约数;

2,再找出自然数\(N_2\)的所有约数;

3,找出两个约数之间重叠的部分。

到这里,我们的所有公约数被找出来了,要求解最大公约数,只要加一步:

4,找出这个重叠部分中最大的那个数。

这样一种朴素的方式去解决这个问题是可以的,但是仔细分析一下,这样是不是耗费资源了,因为公约数被找出两次才能确定下来。这是解决问题的一个方案,但是会是较好的方案吗?

不是,欧几里得找到了更好的方案:

从公约数的性质来说,一个数\(a\)是公约数,那么它是自然数\(N_1\)的约数的同时,也是自然数\(N_2\)的约数

为了利用好这个性质:

我们看一条对于约数一条特性:

\(a\)\(N_1\)的约数,数\(a\)\(N_2\)的约数,那么数a是\(N_1+N_2\)的约数。

这句话是说约数这种性质对于和是封闭的,或者说加法这种运算不会改数\(a\)具备约数的特性。

而且还有一个特性:

\(a\)是N的约数,那么a是\(-N\)的约数,这是对于约数推广到负数后成立的,那么就意味着取负也不会改变一个数具有约数的特性

这两个合起来:

\(a\)\(N_2\)的约数,推出,数\(a\)\(-N_2\)的约数;

\(a\)\(N_1\)的约数;

上面两条推出,数\(a\)\(N_1-N_2\)的约数。

现在我们有三条:

\(a\)\(N_1\)的约数,数\(a\)\(N_2\)的约数,数\(a\)\(N_1-N_2\)的约数。

如果我们总是保证\(N_1> N_2>0\),就是\(N_1,N_2\)是两个自然数,那么

这个数\(N_1-N_2>0\)也是一个自然数,并且\(N_1-N_2\)\(N_1\)小;

这就是说,我们找出了一个比\(N_1\)小的数而且同时保持着数a是它的约数这条性质。

整个思路是这样的:

\(a\)\(N_1\)的约数,数\(a\)\(N_2\)的约数,推理出数\(a\)\(N_1-N_2\)的约数;

现在数\(a\)\(N_1-N_2\)的约数,数\(a\)\(N_2\)的约数,\(N_1-N_2\)比原来的\(N_1\)小;

在这个过程中,没有影响数\(a\)是它们的约数这个事实,而是实现了一次问题规模的缩减,由数\(a\)\(N_1\)\(N_2\)的公约数,缩减成数\(a\)\(N_1-N_2\)\(N_2\)的公约数 。

如果这个缩减过程持续下去,毫无疑问最后会发生的是其\(N_1-N_2=N_2\),或者变成1和某个数的组合。

可以实际进行操作试试:

比如\(N_1=78,N_2=39\)

那么第一次就是\(N_1-N_2=39=N_2\)

或者\(N_1=78,N_2=6\)

\((78,6)->(72,6)->(66,6)->...(6,6)\)

又取一对:

\(N_1=78,N_2=15\)

\((78,15)->(63,15)->(48,15)->(33,15)->\\(18,15)->(3,15)->(15,3)->(12,3)->(9,3)->(6,3)->(3,3)\)

\((3,15)->(15,3)\)只是为了保证\(N_1\)大于\(N_2\),这种调换是可以的,

因为,数a是3的约数,数a是15的约数;

数a是15的约数,数a是3的约数没有区别。

那么又试验一组:

\(N_1=78,N_2=7\)

\((78,7)->(71,7)->(64,7)->(57,7)->(50,7)->\\(43,7)->(36,7)->(29,7)->(22,7)->(15,7)->(8,7)->(1,7)\)

你发现这个方法的好处没有,只要进行有限次的减法运算就可以去找公约数了。

现在我们能确定的是这种方法可以找到一个公约数,现在的问题是,这个公约数是最大的吗?我们来思考这个问题,

最大公约数也满足这种封闭性,就是最大公约数也能被传递,那么这个问题就解决了,因为传递到最后就是两种情况:

1,当\(N_1-N_2=N_2\)时, \(N_1-N_2\)\(N_2\)的最大公约数,这也就是说,两个相等的是的最大公约数是多少,这个问题好回答,这个数本身就是,比如8和8的最大公约数是多少,就是8;

2,如果是1和某个数k的组合,问题变成了1和数k的最大公约数是多少,这个问题回答是1,因为1本身只有一个约数,就是1自己。

这两种情况都被回答了,就是所结果这一头已经不必去考虑了。现在考虑最大公约数也满足这种封闭性。

就是说一个数\(a\)是自然数\(N_1\)和自然数\(N_2\)的最大公约数,那么数a是不是\(N_1-N_2\)\(N_2\)的最大公约数?

这个问题,其实不是很显然,举例是很好说明的,但是证明就要费劲一些,那么留下来就行了。

现在我们继续说欧几里得算法,之前我们的用的是减法,但是我们知道减法一个一个减和两个数直接做除法是一样的。

这样就导致,现在假设用\(N_1/N_2\)

那么有一个等式\(N_1=\lfloor \frac{N_1}{N_2} \rfloor \times N_2+r\)

也就是r=\(N_1-\lfloor \frac{N_1}{N_2} \rfloor \times N_2\),

可以看到,我们把上面的减法用到了极致,一次性减掉\(\lfloor \frac{N_1}{N_2} \rfloor\)\(N_2\),

但是我们最大公约数的性质还是被保留了,\(N_1,N_2\)的最大公约数,变成了\(N_2,r\)的最大公约数。

这样的迭代更加快了,这就是最后版本的欧几里得算法。

posted @ 2021-01-20 16:54  Rivenbar  阅读(112)  评论(0)    收藏  举报