# Steinscher Algorithmus

Der steinsche Algorithmus oder binäre euklidische Algorithmus dient der effizienten Berechnung des größten gemeinsamen Teilers. Der Algorithmus wurde 1967 vom Physiker Josef Stein (Hebräische Universität Jerusalem) vorgestellt. Donald E. Knuth zufolge entwickelten R. Silver und J. Tersian den Algorithmus bereits 1962, publizierten ihn aber nicht.

## Funktionsweise

Der Algorithmus nutzt folgende Rechenregeln:
Falls $b=0$:
* $\operatorname {ggT} (a,\ 0)=a\qquad$ und Haltebedingung des Algorithmus
Falls $b={\text{ungerade}}$:
* $\operatorname {ggT} (a,\ b)={\begin{cases}\operatorname {ggT} (a,\ b-a)\ \ \quad &{\text{falls }}b\geq a\\\operatorname {ggT} (b,\ a-b)\ \ \quad &{\text{sonst }}\end{cases}}$
Falls $b={\text{gerade}}$:
* $\operatorname {ggT} (a,\ b)={\begin{cases}\operatorname {ggT} (a,\ b/2)&{\text{falls }}a{\text{ ungerade}}\\\operatorname {ggT} (a/2,\ b/2)\cdot 2&{\text{sonst }}\end{cases}}$

### Funktionsweise

    a) Nutzt $\operatorname {ggT} (a,\ 0)=a\$ aus und ist gleichzeitig die Haltebedingung des Algorithmus.
    b) Wird abgewendet, wenn $b$ ungerade ist.
       b1) Ist $b\geq a$, wird $b$ um $a$ reduziert. $\operatorname {ggT} (a,\ b)=\operatorname {ggT} (a,\ b-a)$ ausgenutzt.
       b2) Ist $b<a$, wird als erster Operand der zweite Operand $b$ benutzt und als zweiter Operand $a-b$.
          Durch dieses geschicktes Umsortieren wird das Horroszenario des klassischen euklidischen Algorithmus vermieden, in dem ein sehr großer Operand nur sehr langsam reduziert wird.
    c) wird verwendet, wenn $b$ gerade ist:
       c1) Wenn nur ein Operand gerade ist, kann die $2$ als gemeinsamer Teiler gestrichen werden.
       c2) Wenn beide Operanden gerade ist, werde beide um den Teiler $2$ verringert, diese Operation wird sich aber für das Endergebnis gemerkt, da es ja ein gemeinsamer Teiler ist.
Wir benutzen dafür das Horrorszenario für den klassischen euklidischen Algorithmus, zwei große fast gleiche Zahlen $209865$ und $209797$:
    ${\begin{array}{rl|l}\operatorname {ggT} (209865,\ 209797)&=\operatorname {ggT} (209797,\ 68)&\scriptstyle {\text{b2}}\\\operatorname {ggT} (209797,\ 68)&=\operatorname {ggT} (209797,\ 34)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (209797,\ 34)&=\operatorname {ggT} (209797,\ 17)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (209797,\ 17)&=\operatorname {ggT} (17,\ 209780)&\scriptstyle {\text{b2, hier bekommt der klassische euklidische Algorithmus ein Problem, hier wird allerdings eine ungerade Zahl durch Division durch 2 erzeugt und diese nach vorn gebracht}}\\\operatorname {ggT} (17,\ 209780)&=\operatorname {ggT} (17,\ 104890)&\scriptstyle {\text{c1, hier wird entweder halbiert oder diese ungerade Zahl subtrahiert und damit eine gerade Zahl erzeugt}}\\\operatorname {ggT} (17,\ 104890)&=\operatorname {ggT} (17,\ 52445)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 52445)&=\operatorname {ggT} (17,\ 52428)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 52428)&=\operatorname {ggT} (17,\ 26214)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 26214)&=\operatorname {ggT} (17,\ 13107)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 13107)&=\operatorname {ggT} (17,\ 13090)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 13090)&=\operatorname {ggT} (17,\ 6545)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 6545)&=\operatorname {ggT} (17,\ 6528)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 6528)&=\operatorname {ggT} (17,\ 3264)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 3264)&=\operatorname {ggT} (17,\ 1632)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 1632)&=\operatorname {ggT} (17,\ 816)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 816)&=\operatorname {ggT} (17,\ 408)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 408)&=\operatorname {ggT} (17,\ 204)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 204)&=\operatorname {ggT} (17,\ 102)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 102)&=\operatorname {ggT} (17,\ 51)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 51)&=\operatorname {ggT} (17,\ 34)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 34)&=\operatorname {ggT} (17,\ 17)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 17)&=\operatorname {ggT} (17,\ 0)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 0)&=17&\scriptstyle {\text{a}}\\\end{array}}$
Zu beachten ist, dass der steinsche Algorithmus nur dann richtig funktioniert, wenn vorzeichenlose Integer verwendet werden. Negative Zahlen müssen zuerst in positive überführt werden. Der euklidische Algorithmus hingegen funktioniert auch mit vorzeichenbehafteten Integertypen, wenn ein Operand nicht die kleinste darstellbare Zahl ist.

## Prinzip

Zu bestimmen sei der größte gemeinsame Teiler der beiden positiven Zahlen $a$ und $b$. Dazu wird als erstes eine Variable $k$ definiert und dieser wird der Wert 0 zugewiesen. Dann werden sowohl $a$ als auch $b$ solange durch 2 geteilt, bis $a$ und $b$ nicht mehr durch 2 teilbar sind. Bei jeder Halbierung wird $k$ um 1 erhöht.
Der zweite Teil benötigt eine zusätzliche Variable $t$, der die Differenz von $a$ und $b$ zugewiesen wird. Jeder gemeinsame Teiler von $a$ und $b$ ist auch Teiler von $t$, sodass gilt: $\operatorname {ggT} (a,b)=\operatorname {ggT} (a,t)=\operatorname {ggT} (b,t)$. Die Variable $t$ wird anschließend noch, solange es sich um eine gerade Zahl handelt, durch 2 geteilt. Dann wird $a$ durch $t$ ersetzt und mit dem neuen $a$ ein neues $t$ berechnet. Der Algorithmus ist beendet, sobald $t=0$ gilt. Das Ergebnis ist dann $\operatorname {ggT} (a,b)=a\cdot 2^{k}$.

## Algorithmus

Die hier in Pseudocode beschriebene Variante des Algorithmus entspricht im Wesentlichen derjenigen, die Donald E. Knuth in seinem Werk The Art of Computer Programming beschreibt.
Viele Prozessoren haben heutzutage Befehlssätze, die sehr schnell (oft in einem Takt) bestimmen können, wie oft eine Ganzzahl durch Zwei teilbar ist. Zum Beispiel stellt die x86-Architektur seit dem 80386 für diesen Zweck die Instruktion bsf zur Verfügung. Unter Verwendung einer solchen Instruktion ist es möglich, zwei der drei Schleifen des Algorithmus einzusparen und damit seine Laufzeit signifikant zu verbessern. Die folgende Implementierung in der Programmiersprache C nutzt zu diesem Zwecke die POSIX-Standardfunktion ffs (find first set):
Eine Implementierung für vorzeichenlose Ganzzahlen in x86-Assembler, die bsf nutzt:

## Quellen

* ↑ J. Stein: Computational problems associated with Racah algebra. In: Journal of Computational Physics. Band 1, Nr. 3, 1967, ISSN 0021-9991, S. 397–405, doi:10.1016/0021-9991(67)90047-2.
* ↑ Donald E. Knuth: The Art of Computer Programming. Band 2: Seminumerical Algorithms. 3. Auflage. Addison-Wesley Professional, 1997, ISBN 0-201-89684-2, S. 338–341.
* ↑ Alexander Weers: Größter gemeinsamer Teiler. In: Formelsammlung24.de. Archiviert vom Original am 28. März 2018; abgerufen am 27. März 2018.