Diskussion:Steinscher Algorithmus

message: Der Ansicht, dieser Artikel sei nur etwas für Leute mit Fachwissen muß ich energisch widersprechen. Nur naive Jungpennäler werden mit diesen Ausführungen zB ggT(10, 25) lösen können. Wer mehr weiß und versteht, schlägt die Hände über dem Kopf zusammen. Beinahe alle Aussagen oder Sätze sind falsch, mißverständlich, bedenklich oder nur eingeschränkt richtig. Im Einzelnen:
*Der Steinsche Algorithmus ist eben kein "binärer Euklidscher Algorithmus", er hat damit überhaupt nichts zu tun. Da verwechselt jemand den Euklidschen Algorithmus synonym mit GgT-Suche. Siehe englisch "Binary GCD-Algorithm". Der Steinsche und der Euklidischen Algorithmus haben zwar die Subtraktion gemeinsam, aber es führt nicht weiter, aus dieser eher konstruierten Parallelen eine Verwandschaft herzuleiten.
*Ob er der "effizienten Berechnung dient" ist Ansichtsache und von vielen Umständen abhängig.
*Josef Stein war ein israelischer Mathematiker, der um 1930 in Palestina geboren wurde. Bei der Abgabe des Manuskripts 1966 war er Professor an der hebräischen Universität in Jerusalem.
*Die "Rechenregeln" führen nur dann zum richtigen Ergebnis, wenn a und b positiv sind, die Rekursionsfunktion ggT(a, b) als ersten Parameter aber auch negative Werte akzeptiert. Für zwei negative Werte terminiert der Algorithmus zwar auch, aber mit dem falschen Ergebnis. Haben a und b verschiedene Vorzeichen wird die Rekursion endlos, zB ggT(-1, 1). Außerdem fehlt die Terminierungsbedingung: wenn a=b oder a=0 return b.
Der Rest bis zum Abschnitt "Algorithmus" ist kompletter Quatsch. Zunachst müßte geklärt werden, welcher Euklidische Algorithmus gemeint ist, der mit Subtraktion oder der mit Modulo, beide sind gleichermaßen über 2000 Jahre alt, zu Euklids Zeit wurde aber nur die Subtraktionsversion mit geometrischen Methoden bewiesen. Welche "meisten Prozessoren" haben eigentlich "ein effizientes Schieberegister"? Ich kenne keinen! Keinen Z80, Intel 80x8x, Pentium, Motorola 68k oder PowerPC Siemens 8015++... Alle unterstützen Schieben im Akkumulator oder den Universalregistern. Schieben kann auch nur für positive Zahlen die Division durch 2 ersetzen. Der angegebene Pseudocode funktioniert also nicht mit Schieben, weil die Hilfszahl t negativ werden darf und soll. Der Pseudocode ist aber ohnehin nicht besonders praktikabel, zur Demonstration (Knuth) oder für Pennäler reicht es aber.
Der Steinsche Algorithmus ist in jedem mathematischen oder Zahlensystem vorteilhaft, in dem eine Subtraktion und eine Division durch 2 deutlich schneller sind, als eine Modulooperation mit großen Zahlen. Das gilt zB sehr anschaulich für handschriftliche Rechnung im Dezimalsystem. Auf automatischen Rechenmaschinen muß zusätzlich sicher sein, daß die zusätzlichen Abfragen (gerade, Vorzeichen, Vergleich) und die Subtraktion nicht zu aufwendig sind. Außerdem muß die Programmiersprache die schnelle Division durch 2 oder binäres Schieben unterstützen.
Die Anmerkungen:
*Ob der verwendete Datentyp negative Zahlen darstellen kann oder nicht ist für beide Algorithem unerheblich, es sei denn, man programmiert sie so, daß es eine Rolle spielt, wie im Pseudocode. Beide oder alle drei Algorithmen liefern nur für positive Zahlen sinnvolle Ergebnisse.
*Der Effizienzvergleich zwischen den Algorithmen hat nichts mit Registern und Integern zu tun, sondern ausschließlich mit der Effizienz der verwendeten Rechenoperationen. Wenn die Division durch 2 nicht wesentlich schneller ist als die allgemeine Division, nützt der Steinsche Algorithmus auch nichts. Eventuelll sind ja auch die Vergleiche oder die Subtraktion teuer.
PositiverInt ggTStein(PositiverInt a, PositiverInt b)
    {
    if      (a == 0)           return  b;	// triviale Lösung
    else if (b == 0)           return  a;	// triviale Lösung
    else if (a == b)           return  b;	// normales Rekursionsende
    else if ((a mod 2) == 0)
         if ((b mod 2) == 0)   return  ggTStein( a/2,  b/2) * 2;
         else                  return  ggTStein( a/2,  b  );
    else if ((b mod 2) == 0)   return  ggTStein( b/2,  a  );
    else if (a < b)            return  ggTStein((b-a)/2, a);
         else                  return  ggTStein((a-b)/2, b);
    }
Ich vermisse auch die Erweiterung nach Richard Brent und H.T. Kung mit einer Division durch 4. Diese lohnt sich, wenn man sehr preiswert (a mod 4) und (b mod 4) zB durch maskieren des niederwertigisten Byte ermitteln kann.
PositiverInt ggTBrentKung(PositiverInt a, PositiverInt b)
    {
    if      (a == 0)                  return  b;	// triviale Lösung
    else if (b == 0)                  return  a;	// triviale Lösung
    else if (a == b)                  return  b;	// normales Rekursionsende
    else if ((a mod 2) == 0)
         if ((b mod 2) == 0)          return  ggTBrentKung( a/2,  b/2) * 2;
         else                         return  ggTBrentKung( a/2,  b  );
    else if ((b mod 2) == 0)          return  ggTBrentKung( b/2,  a  );
    else if ((a mod 4) == (b mod 4))
         if (a < b)                   return  ggTBrentKung((b-a)/4, a);
         else                         return  ggTBrentKung((a-b)/4, b);
    else if (a < b)                   return  ggTBrentKung((a+b)/4, a);
         else                         return  ggTBrentKung((a+b)/4, b);
    // Für einen günstigeren Worst Case können die letzten beiden Zeilen
    //  durch den Steinschen Algorithmus ersetzt werden, muss aber nicht
//  else if (a < b)                   return  ggTBrentKung((b-a)/2, a);
//       else                         return  ggTBrentKung((a-b)/2, b);
    }
Rekursive Lösungen sehen zwar oft elegant aus, sind aber selten schnell, resourcenschonend oder efizient. Man wird diese Codebeispiele also kaum für die Untersuchung von Zahlen mit vielen Millionen Stellen verwenden, da die Rekursionstiefe linear von der Stellenzahl abhängt. Für diese Aufgaben sind aber die Algorithmen von Stein oder Brent/Kung besonders interessant.--46.115.140.103 10:40, 24. Jan. 2014 (CET)
thread_title:  Boa, echt, ey 

message: Folgender Abschnitt ist falsch:
* Der steinsche Algorithmus ist auf heutigen Rechnern nur dann effizienter, wenn der Integertyp nicht in ein Register hineinpasst, also mehrere Zugriffe pro Variable benötigt werden. Das ist beispielsweise bei 64-Bit Integerzahlen auf einem Rechner mit 32-Bit Registern der Fall. Umgekehrt ist der euklidische schneller, wenn der Integertyp vollständig in ein Register passt, eine Variable also nur einen einzelnen Zugriff benötigt.
Es kostet zwar nur eine Instruktion, diese Instruktion kostet aber viele Zyklen. Moderne CPUs haben eine Instruktion zum Zählen von Nullen am Ende einer Zahl. Diese Instruktion ist sehr schnell, Bitverschiebungen ebenso.
Eigene Implementationen zeigen Geschwindigkeitserhöhungen von 40% - 200% (je nach Integervariablengröße). Dieser Blogpost zeigt ebenfalls deutliche Verbesserungen und auch die hochoptimierte GMP-Bibliothek für beliebig große Ganzzahlen nutzt den Steinschen Algorithmus (allerdings nur für kleine Bigints) Beweis.
Die Aussage ist also falsch herum. Wenn Integertypen in ein Register passen ist Stein schneller. Euklid ist nur dann schneller, wenn Division schneller ist als Nullenzählen und Bitverschieben. Das ist architekturabhängig, sollte aber nur selten der Fall sein. Bei großen Zahlen gibt es asymptotisch bessere Algorithmen. --134.130.4.241 18:00, 7. Sep. 2015 (CEST)
thread_title:  Geschwindigkeit 

message: Es gab hier Unstimmigkeiten, ob er Deutscher oder Israeli ist. Das einzige, was sich mit den angegebenen Quellen belegen läßt, ist seine damalige Tätigkeit an der Hebrew University, weshalb ich die Angabe Deutscher/Israeli durch diese Angabe ersetzen werde.—Hoegiro (Diskussion) 18:34, 29. Okt. 2020 (CET)
thread_title:  Josef Stein