Zeitliche Komplexität des Euklid-Algorithmus


97

Ich habe Schwierigkeiten zu entscheiden, wie zeitlich komplex Euklids größter gemeinsamer Nenner-Algorithmus ist. Dieser Algorithmus im Pseudocode lautet:

function gcd(a, b)
    while b ≠ 0
       t := b
       b := a mod b
       a := t
    return a

Es scheint von a und b abzuhängen . Ich denke, dass die zeitliche Komplexität O ist (a% b). Ist das korrekt? Gibt es einen besseren Weg, das zu schreiben?


14
Siehe Knuth TAOCP, Band 2 - er gibt die ausführliche Berichterstattung. Nur FWIW, ein paar Leckerbissen: Es ist nicht proportional zu a%b. Der schlimmste Fall ist, wenn aund bsind aufeinanderfolgende Fibonacci-Zahlen.
Jerry Coffin

3
@ JerryCoffin Hinweis: Wenn Sie beweisen möchten, dass der schlimmste Fall tatsächlich Fibonacci-Zahlen sind, sollten Sie in Betracht ziehen, den n-ten Schritt vor der Beendigung zu beweisen, der mindestens so groß sein muss wie das gcd-fache der n-ten Fibonacci-Zahl mit mathematischer Induktion.
Mygod

Antworten:


73

Ein Trick zur Analyse der zeitlichen Komplexität des Euklid-Algorithmus besteht darin, zu verfolgen, was in zwei Iterationen geschieht:

a', b' := a % b, b % (a % b)

Jetzt nehmen a und b statt nur eines ab, was die Analyse erleichtert. Sie können es in Fälle unterteilen:

  • Winzig A: 2a <= b
  • Winziges B: 2b <= a
  • Kleines A: 2a > babera < b
  • Kleines B: 2b > aaberb < a
  • Gleich: a == b

Jetzt zeigen wir, dass jeder einzelne Fall die Summe a+bum mindestens ein Viertel verringert :

  • Winzig A: b % (a % b) < aund 2a <= b, so bwird um mindestens die Hälfte a+bverringert , so um mindestens verringert25%
  • Winziges B: a % b < bund 2b <= awird also aum mindestens die Hälfte a+bverringert , also um mindestens die Hälfte verringert25%
  • Kleines A: bwird b-a, was kleiner als ist b/2, a+bmindestens um abnehmend 25%.
  • Kleines B: awird a-b, was kleiner als ist a/2, a+bmindestens um abnehmend 25%.
  • Gleich: a+bfällt auf 0, was offensichtlich a+bum mindestens abnimmt 25%.

Daher verringert sich a+bdurch Fallanalyse jeder Doppelschritt um mindestens 25%. Es gibt eine maximale Anzahl von Malen, die passieren können, bevor a+bsie nach unten fallen müssen 1. Die Gesamtzahl der Schritte ( S), bis wir 0 erreichen, muss erfüllt sein (4/3)^S <= A+B. Jetzt arbeite es einfach:

(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)

Die Anzahl der Iterationen ist also linear in der Anzahl der Eingangsziffern. Für Zahlen, die in CPU-Register passen, ist es sinnvoll, die Iterationen so zu modellieren, dass sie eine konstante Zeit benötigen, und so zu tun, als ob die Gesamtlaufzeit der GCD linear wäre.

Wenn Sie mit großen Ganzzahlen arbeiten, müssen Sie natürlich berücksichtigen, dass die Moduloperationen innerhalb jeder Iteration keine konstanten Kosten verursachen. Grob gesagt wird die gesamte asymptotische Laufzeit das n ^ 2-fache eines polylogarithmischen Faktors betragen. So etwas wie n^2 lg(n) 2^O(log* n) . Der polylogarithmische Faktor kann vermieden werden, indem stattdessen ein binärer gcd verwendet wird .


Können Sie bitte erklären, warum "b% (a% b) <a"?
Michael Heidelberg

3
@MichaelHeidelberg x % ykann nicht mehr als sein xund muss kleiner sein als y. Ist a % balso höchstens agezwungen b % (a%b), unter etwas zu sein, das höchstens aund daher insgesamt kleiner ist als a.
Craig Gidney

@ Cheersandhth.-Alf Sie halten einen kleinen Unterschied in der bevorzugten Terminologie für "ernsthaft falsch"? Natürlich habe ich CS-Terminologie verwendet; Es ist eine Informatikfrage. Unabhängig davon habe ich die Antwort klargestellt und "Anzahl der Ziffern" angegeben.
Craig Gidney

@CraigGidney: Danke, dass du das behoben hast. Jetzt erkenne ich das Kommunikationsproblem an vielen Wikipedia-Artikeln, die von reinen Akademikern geschrieben wurden. Bedenken Sie Folgendes: Der Hauptgrund, über die Anzahl der Ziffern zu sprechen, anstatt nur O (log (min (a, b)) zu schreiben, wie ich es in meinem Kommentar getan habe, besteht darin, die Dinge für nicht-mathematische Leute einfacher zu verstehen. Ohne das Sorge nur „log“, etc. So schreiben, das ist Zweck der Anzahl der Stellen, diese herausgefordert Leute zu helfen. Wenn Sie nennen diesen Begriff „Größe“ und haben die Definition an anderer Stelle, und reden nicht über „log“ in der Ende, Sie dunkel statt Hilfe.
Prost und hth. - Alf

Der letzte Absatz ist falsch. Wenn Sie die relevanten Teleskopreihen summieren, werden Sie feststellen, dass die Zeitkomplexität nur O (n ^ 2) ist, selbst wenn Sie den quadratischen Zeitteilungsalgorithmus des Schulbuchs verwenden.
Emil Jeřábek

27

Die geeignete Methode zur Analyse eines Algorithmus besteht darin, seine Worst-Case-Szenarien zu ermitteln. Der schlimmste Fall der euklidischen GCD tritt auf, wenn Fibonacci-Paare beteiligt sind. void EGCD(fib[i], fib[i - 1]), wo i> 0.

Entscheiden wir uns zum Beispiel für den Fall, dass die Dividende 55 und der Divisor 34 beträgt (denken Sie daran, dass es sich immer noch um Fibonacci-Zahlen handelt).

Geben Sie hier die Bildbeschreibung ein

Wie Sie vielleicht bemerken, kostete dieser Vorgang 8 Iterationen (oder rekursive Aufrufe).

Versuchen wir es mit größeren Fibonacci-Zahlen, nämlich 121393 und 75025. Wir können auch hier feststellen, dass 24 Iterationen (oder rekursive Aufrufe) erforderlich waren.

Geben Sie hier die Bildbeschreibung ein

Sie können auch feststellen, dass jede Iteration eine Fibonacci-Zahl ergibt. Deshalb haben wir so viele Operationen. Wir können ähnliche Ergebnisse nicht nur mit Fibonacci-Zahlen erzielen.

Daher wird die Zeitkomplexität diesmal durch ein kleines Oh (Obergrenze) dargestellt. Die Untergrenze ist intuitiv Omega (1): Fall von 500 geteilt durch 2 zum Beispiel.

Lösen wir die Wiederholungsrelation:

Geben Sie hier die Bildbeschreibung ein

Wir können dann sagen, dass die euklidische GCD höchstens eine log (xy) -Operation ausführen kann .


2
Ich denke, diese Analyse ist falsch, weil die Basis von der Eingabe abhängt.
Hoffentlich

Können Sie beweisen, dass eine abhängige Basis ein Problem darstellt?
Mohamed Ennahdi El Idrissi

1
Die Basis ist offensichtlich der goldene Schnitt. Warum? Weil es genau einen zusätzlichen Schritt dauert, um nod (13,8) vs nod (8,5) zu berechnen. Für ein festes x ist, wenn y <x, die schlechteste Leistung x = fib (n + 1), y = fib (n). Hier hängt y von x ab, also können wir nur x betrachten.
Stepan

17

Das finden Sie im Wikipedia-Artikel .

Es hat sogar eine schöne Darstellung der Komplexität für Wertepaare.

Es ist nicht O(a%b) .

Es ist bekannt (siehe Artikel), dass niemals mehr Schritte als die fünffache Anzahl von Ziffern in der kleineren Anzahl ausgeführt werden. Die maximale Anzahl von Schritten wächst also mit der Anzahl der Ziffern (ln b). Die Kosten für jeden Schritt steigen auch mit der Anzahl der Stellen, sodass die Komplexität daran gebunden ist, O(ln^2 b)dass b die kleinere Zahl ist. Das ist eine Obergrenze, und die tatsächliche Zeit ist normalerweise kürzer.


Was bedeutet n?
IVlad

@IVlad: Anzahl der Ziffern. Ich habe die Antwort geklärt, danke.
JoshD

Für den OP-Algorithmus, der (große Ganzzahl-) Divisionen (und keine Subtraktionen) verwendet, ist dies tatsächlich eher wie O (n ^ 2 log ^ 2n).
Alexandre C.

@Alexandre C.: Denken Sie daran n = ln b. Was ist die reguläre Komplexität des Moduls für Big Int? Ist es O (log n log ^ 2 log n)
JoshD

@JoshD: es ist so etwas, ich glaube ich habe einen log n Term verpasst, die endgültige Komplexität (für den Algorithmus mit Divisionen) ist in diesem Fall O (n ^ 2 log ^ 2 n log n).
Alexandre C.

13

Siehe hier .

Insbesondere dieser Teil:

Lamé zeigte, dass die Anzahl der Schritte, die erforderlich sind, um den größten gemeinsamen Teiler für zwei Zahlen kleiner als n zu erreichen, gleich ist

Alt-Text

So O(log min(a, b))ist eine gute Obergrenze.


3
Dies gilt für die Anzahl der Schritte, berücksichtigt jedoch nicht die Komplexität jedes Schritts selbst, die mit der Anzahl der Ziffern (ln n) skaliert.
JoshD

9

Hier ist ein intuitives Verständnis der Laufzeitkomplexität des Euclid-Algorithmus. Die formalen Beweise werden in verschiedenen Texten wie Einführung in Algorithmen und TAOCP Vol 2 behandelt.

Denken Sie zuerst darüber nach, was wäre, wenn wir versuchen würden, gcd von zwei Fibonacci-Zahlen F (k + 1) und F (k) zu nehmen. Sie können schnell feststellen, dass der Euklid-Algorithmus zu F (k) und F (k-1) iteriert. Das heißt, mit jeder Iteration bewegen wir uns in der Fibonacci-Reihe um eine Zahl nach unten. Da Fibonacci-Zahlen O (Phi ^ k) sind, wobei Phi der goldene Schnitt ist, können wir sehen, dass die Laufzeit von GCD O (log n) war, wobei n = max (a, b) und log die Basis von Phi hat. Als nächstes können wir beweisen, dass dies der schlimmste Fall ist, indem wir beobachten, dass Fibonacci-Zahlen konsistent Paare erzeugen, bei denen die Reste in jeder Iteration groß genug bleiben und niemals Null werden, bis Sie am Anfang der Serie angekommen sind.

Wir können O (log n), wobei n = max (a, b) gebunden ist, noch enger machen. Angenommen, b> = a, damit wir gebunden an O schreiben können (log b). Beobachten Sie zunächst, dass GCD (ka, kb) = GCD (a, b) ist. Da die größten Werte von k gcd (a, c) sind, können wir b in unserer Laufzeit durch b / gcd (a, b) ersetzen, was zu einer engeren Grenze von O führt (log b / gcd (a, b)).


Können Sie einen formalen Beweis dafür liefern, dass Fibonacci nos den schlimmsten Fall für Euklids algo produzieren?
Akash

4

Der schlimmste Fall des Euklid-Algorithmus ist, wenn die Reste bei jedem Schritt so groß wie möglich sind, d. H. für zwei aufeinanderfolgende Terme der Fibonacci-Sequenz.

Wenn n und m die Anzahl der Stellen von a und b sind, wobei n> = m angenommen wird, verwendet der Algorithmus O (m) -Divisionen.

Beachten Sie, dass die Komplexität immer in Bezug auf die Größe der Eingaben angegeben wird, in diesem Fall in Bezug auf die Anzahl der Ziffern.


4

Der schlimmste Fall tritt auf, wenn sowohl n als auch m aufeinanderfolgende Fibonacci-Zahlen sind.

gcd (Fn, Fn - 1) = gcd (Fn - 1, Fn - 2) = ⋯ = gcd (F1, F0) = 1 und die n-te Fibonacci-Zahl ist 1,618 ^ n, wobei 1,618 der goldene Schnitt ist.

Um gcd (n, m) zu finden, ist die Anzahl der rekursiven Aufrufe Θ (logn).


3

Hier ist die Analyse im Buch Datenstrukturen und Algorithmusanalyse in C von Mark Allen Weiss (zweite Ausgabe, 2.4.4):

Der Euklid-Algorithmus berechnet kontinuierlich Reste, bis 0 erreicht ist. Der letzte Rest ungleich Null ist die Antwort.

Hier ist der Code:

unsigned int Gcd(unsigned int M, unsigned int N)
{

    unsigned int Rem;
    while (N > 0) {
        Rem = M % N;
        M = N;
        N = Rem;
    }
    Return M;
}

Hier ist ein Satz , den wir verwenden werden:

Wenn M> N, dann ist M mod N <M / 2.

BEWEIS:

Es gibt zwei Fälle. Wenn N <= M / 2 ist, gilt der Satz für diesen Fall, da der Rest kleiner als N ist. Der andere Fall ist N> M / 2. Aber dann geht N einmal mit einem Rest M - N <M / 2 in M, was den Satz beweist.

Wir können also folgende Schlussfolgerung ziehen:

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

Nach zwei Iterationen beträgt der Rest höchstens die Hälfte seines ursprünglichen Werts. Dies würde zeigen, dass die Anzahl der Iterationen höchstens ist 2logN = O(logN).

Beachten Sie, dass der Algorithmus Gcd (M, N) unter der Annahme von M> = N berechnet. (Wenn N> M ist, werden sie durch die erste Iteration der Schleife ausgetauscht.)


2

Der Satz von Gabriel Lame begrenzt die Anzahl der Schritte durch log (1 / sqrt (5) * (a + 1/2)) - 2, wobei die Basis des log (1 + sqrt (5)) / 2 ist. Dies ist das Worst-Case-Szenario für den Algorithmus und tritt auf, wenn die Eingaben aufeinanderfolgende Fibanocci-Zahlen sind.

Eine etwas liberalere Grenze ist: log a, wobei die Basis des log (sqrt (2)) von Koblitz impliziert wird.

Für kryptografische Zwecke berücksichtigen wir normalerweise die bitweise Komplexität der Algorithmen, wobei berücksichtigt wird, dass die Bitgröße ungefähr durch k = loga gegeben ist.

Hier ist eine detaillierte Analyse der bitweisen Komplexität des Euklid-Algorithmus:

Obwohl in den meisten Referenzen die bitweise Komplexität des Euklid-Algorithmus durch O (loga) ^ 3 gegeben ist, gibt es eine engere Grenze, die O (loga) ^ 2 ist.

Erwägen; 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.

Beachten Sie Folgendes: a = r0> = b = r1> r2> r3 ...> rm-1> rm> 0 .......... (1)

und rm ist der größte gemeinsame Teiler von a und b.

Durch eine Behauptung in Koblitz 'Buch (Ein Kurs in Zahlentheorie und Kryptographie) kann bewiesen werden, dass: ri + 1 <(ri-1) / 2 ................. ( 2)

Wiederum in Koblitz wird die Anzahl der Bitoperationen, die erforderlich sind, um eine positive k-Bit-Ganzzahl durch eine positive l-Bit-Ganzzahl (unter der Annahme von k> = l) zu teilen, wie folgt angegeben: (k-l + 1) .l ...... .............(3)

Nach (1) und (2) ist die Anzahl der Teilungen O (loga), und nach (3) ist die Gesamtkomplexität O (loga) ^ 3.

Dies kann nun durch eine Bemerkung in Koblitz auf O (loga) ^ 2 reduziert werden.

Betrachten Sie ki = logri +1

durch (1) und (2) haben wir: ki + 1 <= ki für i = 0,1, ..., m-2, m-1 und ki + 2 <= (ki) -1 für i = 0 , 1, ..., m-2

und durch (3) sind die Gesamtkosten der m Divisionen begrenzt durch: SUMME [(ki-1) - ((ki) -1))] * ki für i = 0,1,2, .., m

Neuordnung: SUM [(ki-1) - ((ki) -1))] * ki <= 4 * k0 ^ 2

Die bitweise Komplexität von Euklids Algorithmus ist also O (loga) ^ 2.


1

Für den iterativen Algorithmus haben wir jedoch:

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;
}

Bei Fibonacci-Paaren gibt es keinen Unterschied zwischen iterativeEGCD()und iterativeEGCDForWorstCase()wo letzteres wie folgt aussieht:

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;
}

Ja, mit Fibonacci-Paaren n = a % nundn = a - n es ist genau das Gleiche.

Wir wissen auch, dass in einer früheren Antwort auf dieselbe Frage ein abnehmender Faktor vorherrscht: factor = m / (n % m) .

Um die iterative Version der euklidischen GCD in einer definierten Form zu gestalten, können wir daher Folgendes als "Simulator" darstellen:

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);
}

Basierend auf der Arbeit (letzte Folie) von Dr. Jauhar Ali ist die obige Schleife logarithmisch.

Geben Sie hier die Bildbeschreibung ein

Ja, klein Oh, weil der Simulator höchstens die Anzahl der Iterationen angibt . Nicht-Fibonacci-Paare würden eine geringere Anzahl von Iterationen benötigen als Fibonacci, wenn sie auf euklidischer GCD untersucht würden.


Da diese Studie in der Sprache C durchgeführt wurde, können Präzisionsprobleme zu fehlerhaften / ungenauen Werten führen. Aus diesem Grund wurde long long verwendet, um die Gleitkommavariable mit dem Namen factor besser anzupassen . Der verwendete Compiler ist MinGW 2.95.
Mohamed Ennahdi El Idrissi

1

Bei jedem Schritt gibt es zwei Fälle

b> = a / 2, dann macht a, b = b, a% b b höchstens die Hälfte seines vorherigen Wertes

b <a / 2, dann macht a, b = b, a% b höchstens die Hälfte seines vorherigen Wertes, da b kleiner als a / 2 ist

Bei jedem Schritt reduziert der Algorithmus mindestens eine Zahl auf mindestens die Hälfte weniger.

In höchstens O (log a) + O (log b) wird dies auf die einfachen Fälle reduziert. Was einen O (log n) -Algorithmus ergibt, wobei n die Obergrenze von a und b ist.

Ich habe es hier gefunden

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.