Answers:
分析Euclid算法的时间复杂度的一个技巧是遵循两次迭代中发生的情况:
a', b' := a % b, b % (a % b)
现在,a和b都将减少,而不是仅减少一个,这使得分析更加容易。您可以将其分为几种情况:
2a <= b
2b <= a
2a > b
但是a < b
2b > a
但是b < a
a == b
现在,我们将显示每个案例都会使总数减少a+b
至少四分之一:
b % (a % b) < a
和2a <= b
,因此b
减少了至少一半,因此a+b
减少了至少25%
a % b < b
和2b <= a
,因此a
减少了至少一半,因此a+b
减少了至少25%
b
将变为b-a
,小于至少b/2
减少。a+b
25%
a
将变为a-b
,小于至少a/2
减少a+b
25%
。a+b
降至0
,明显降低a+b
了25%
。因此,通过案例分析,每个双步步数a+b
至少减少了25%
。在a+b
被迫降至之下之前,这种情况最多会发生一次1
。S
直到达到0为止的总步数()必须满足(4/3)^S <= A+B
。现在就工作:
(4/3)^S <= A+B
S <= lg[4/3](A+B)
S is O(lg[4/3](A+B))
S is O(lg(A+B))
S is O(lg(A*B)) //because A*B asymptotically greater than A+B
S is O(lg(A)+lg(B))
//Input size N is lg(A) + lg(B)
S is O(N)
因此,迭代次数与输入位数成线性关系。对于适合cpu寄存器的数字,将迭代建模为采用恒定时间并假装gcd 的总运行时间是线性的是合理的。
当然,如果要处理大整数,则必须考虑以下事实:每次迭代中的模运算没有固定成本。粗略地讲,总渐近运行时间将是多对数因子的n ^ 2倍。有点像 n^2 lg(n) 2^O(log* n)
。可以通过使用二进制gcd来避免多对数因子。
x % y
不能大于x
且必须小于y
。a % b
最多也是如此a
,强迫b % (a%b)
低于最多的东西,a
因此总的来说小于a
。
分析算法的合适方法是确定最坏情况。涉及斐波那契对时,欧几里得GCD最坏的情况发生。
void EGCD(fib[i], fib[i - 1])
,其中i> 0。
例如,让我们选择股息为55,除数为34的情况(回想一下我们仍在处理斐波那契数)。
您可能会注意到,此操作花费了8次迭代(或递归调用)。
让我们尝试更大的斐波那契数,即121393和75025。在此我们还可以注意到,它花了24次迭代(或递归调用)。
您还可以注意到,每次迭代都会产生一个斐波那契数。这就是为什么我们要进行如此多的操作。实际上,仅斐波那契数不能获得相似的结果。
因此,这次将以小Oh(上限)表示时间复杂度。下界直观上是Omega(1):例如,用500除以2的情况。
让我们解决递归关系:
我们可以说,然后欧几里德GCD可以使日志(XY)操作最多。
维基百科的文章对此有很好的了解。
它甚至对值对都有一个很好的复杂度图。
它不是 O(a%b)
。
众所周知(请参阅文章),它所采取的步骤绝不会超过较小数字位数的五倍。因此,最大步数随着位数的增加而增加(ln b)
。每个步骤的成本也随着位数的增加而增加,因此复杂性受O(ln^2 b)
b较小的数字所限制。这是一个上限,实际时间通常较少。
n
代表?
n = ln b
。大整数的模数的规则复杂度是多少?是O(log n log ^ 2 log n)
这是对Euclid算法运行时复杂性的直观理解。正式证明涵盖在各种文本中,例如算法简介和TAOCP第2卷。
首先考虑一下,如果我们尝试取两个斐波那契数F(k + 1)和F(k)的gcd怎么办。您可能会很快观察到Euclid的算法迭代到F(k)和F(k-1)。也就是说,在每次迭代中,我们将斐波那契数列向下移动一个数字。由于斐波那契数为O(Phi ^ k),其中Phi是黄金比率,因此我们可以看到GCD的运行时间为O(log n),其中n = max(a,b),log具有Phi的底数。接下来,我们可以通过观察斐波那契数始终产生对,以确保余数在每次迭代中保持足够大,直到您到达该系列的开始才变为零,从而证明这是最坏的情况。
我们可以使O(log n)的约束更严格,其中n = max(a,b)。假设b> = a,因此我们可以在O(log b)处写bound。首先,观察GCD(ka,kb)= GCD(a,b)。由于k的最大值是gcd(a,c),我们可以在运行时中将b替换为b / gcd(a,b),从而使O的界限更加严格(log b / gcd(a,b))。
下面是书中的分析数据结构与算法分析- C由马克·艾伦·韦斯(第二版,2.4.4):
Euclid算法通过连续计算余数直到达到0来工作。最后的非零余数就是答案。
这是代码:
unsigned int Gcd(unsigned int M, unsigned int N)
{
unsigned int Rem;
while (N > 0) {
Rem = M % N;
M = N;
N = Rem;
}
Return M;
}
这是我们将要使用的一个定理:
如果 M> N,则 M mod N <M / 2。
证明:
有两种情况。如果N <= M / 2,则由于余数小于N,因此该定理在这种情况下成立。另一种情况是N> M / 2。但是随后N进入M一次,余数M-N <M / 2,证明了定理。
因此,我们可以做出以下推断:
Variables M N Rem
initial M N M%N
1 iteration N M%N N%(M%N)
2 iterations M%N N%(M%N) (M%N)%(N%(M%N)) < (M%N)/2
因此,经过两次迭代,其余部分最多为原始值的一半。这将表明迭代次数最多
2logN = O(logN)
。请注意,假设M> = N,该算法将计算Gcd(M,N)(如果N> M,则循环的第一次迭代会交换它们。)
加布里埃尔·拉姆(Gabriel Lame)定理用log(1 / sqrt(5)*(a + 1/2))-2限制步数,其中对数的底数是(1 + sqrt(5))/ 2。这是该算法最坏的情况,当输入是连续的Fibanocci数时发生。
更为宽松的限制是:日志a,Koblitz隐含了日志的底数为(sqrt(2))的日志。
为了进行加密,我们通常考虑算法的按位复杂度,同时考虑到位大小大约由k = loga给出。
这是对欧几里得·阿尔戈里斯(Euclid Algorith)的按位复杂度的详细分析:
尽管在大多数参考文献中,欧几里德算法的按位复杂度由O(loga)^ 3给出,但存在一个更严格的界限,即O(loga)^ 2。
考虑; r0 = a,r1 = b,r0 = q1.r1 + r2。。。,ri-1 = qi.ri + ri + 1,。。。,rm-2 = qm-1.rm-1 + rm rm-1 = qm.rm
观察到:a = r0> = b = r1> r2> r3 ...> rm-1> rm> 0 .....(1)
rm是a和b的最大公约数。
通过Koblitz的著作(数论与密码学课程)的证明,可以证明:ri + 1 <(ri-1)/ 2 .................( 2)
同样在Koblitz中,将k位正整数除以l位正整数(假设k> = l)所需的位数为:(k-l + 1).l ...... .............(3)
通过(1)和(2),除数为O(loga),因此通过(3),总复杂度为O(loga)^ 3。
现在可以通过Koblitz中的注释将其减少为O(loga)^ 2。
考虑ki = logri +1
由(1)和(2)得到:ki + 1 <= ki for i = 0,1,...,m-2,m-1和ki + 2 <=(ki)-1 for i = 0 ,1,...,m-2
并由(3)m个总成本的总和为:i = 0,1,2,..,m的SUM [(ki-1)-((ki)-1))] ki
重新排列此内容:SUM [(ki-1)-((ki)-1))] * ki <= 4 * k0 ^ 2
因此,欧几里得算法的按位复杂度为O(loga)^ 2。
但是,对于迭代算法,我们有:
int iterativeEGCD(long long n, long long m) {
long long a;
int numberOfIterations = 0;
while ( n != 0 ) {
a = m;
m = n;
n = a % n;
numberOfIterations ++;
}
printf("\nIterative GCD iterated %d times.", numberOfIterations);
return m;
}
与斐波那契数对,有什么区别iterativeEGCD()
和iterativeEGCDForWorstCase()
其中后者如下所示:
int iterativeEGCDForWorstCase(long long n, long long m) {
long long a;
int numberOfIterations = 0;
while ( n != 0 ) {
a = m;
m = n;
n = a - n;
numberOfIterations ++;
}
printf("\nIterative GCD iterated %d times.", numberOfIterations);
return m;
}
是的,对于斐波那契货币对n = a % n
和n = a - n
,这是完全一样的。
我们还知道,在对同一问题的较早答复中,存在一个主要的递减因素:factor = m / (n % m)
。
因此,为了以定义的形式形成欧几里得GCD的迭代版本,我们可以将其描述为“模拟器”,如下所示:
void iterativeGCDSimulator(long long x, long long y) {
long long i;
double factor = x / (double)(x % y);
int numberOfIterations = 0;
for ( i = x * y ; i >= 1 ; i = i / factor) {
numberOfIterations ++;
}
printf("\nIterative GCD Simulator iterated %d times.", numberOfIterations);
}
根据Jauhar Ali博士的工作(最后一张幻灯片),上面的循环是对数的。
是的,太小了,因为模拟器最多可以告诉迭代次数。当在欧几里得GCD上进行探测时,非斐波那契对的迭代次数将少于斐波那契。
a%b
。最坏的情况是当a
和b
是连续的斐波那契数时。