Zahlbereiche

Werbung
Kapitel II
Zahlbereiche
Algorithmen bauen auf Elementaroperationen auf, und neue mathematische Begriffe können basierend auf existierenden Begriffen definiert werden. Am Anfang
einer derartigen Entwicklung müssen aber gewisse Objekte und Operationen als
gegeben angenommen werden. In einem theoretischen Aufbau der Mathematik
sind dies die Axiome, die als Basis für den Aufbau einer Theorie zu dienen haben,
als Beispiele seien etwa die Zermelo1 -Fraenkel2 Axiome für die Mengenlehre oder
die Peano3-Axiome für die natürlichen Zahlen genannt. Von einem theoretischne
Standpunkt aus reichen Mengen und die darauf axiomatisch festgelegten Operationen aus, um alle in der Mathematik auftretenden Objekte und Begriffe zu
beschreiben. In einem algorithmischen Aufbau der Mathematik empfiehlt es sich
jedoch, die auf einem Computer in natürlicher Weise vorhandenen Operationen
als Elementaroperationen und die zur Verfügung stehenden Grunddatentypen als
Grundobjekte anzunehmen und darauf aufbauend neue Datenstrukturen und neue
Algorithmen zu entwickeln. Wir werden nun untersuchen, welche Grundstrukturen
auf einem Computer anzutreffen sind, und wie damit verschiedene Arten von Zahlen dargestellt und darauf deren arithmetische Grundoperationen wie Addition,
Multiplikation oder Division realisiert werden können.
6 N und Z
Schon in den einleitenden Betrachtungen zur Umsetzung von mathematischen Algorithmen auf einem Computer in Abschnitt 1 sind wir der Problematik begegnet,
dass unendliche Mengen auf einem Rechner schwer realisierbar sind, und wir in
solchen Fällen immer mit gewissen Unzulänglichkeiten und/oder Fehlern rechnen
0 <Id:
NZQR.tex 547 2007-12-07 15:18:31Z WW >
Ernst: historische Daten
2 Fraenkel, Abraham: historische Daten
3 Peano, Giuseppe: historische Daten
1 Zermelo,
64
Kapitel II. Zahlbereiche
müssen. Die natürlichen Zahlen N und darauf aufbauend die ganzen Zahlen Z sind
die beinahe einfachsten mathematischen Zahlenmengen, aber auch hier haben wir
es bekanntlich mit unendlichen Mengen zu tun.
Darstellung am Computer und arithmetische Grundoperationen
Wir widmen uns vorerst den natürlichen Zahlen, da sich die ganzen Zahlen daraus
(relativ) einfach durch Hinzunahme der negativen natürlichen Zahlen“ ergeben.
”
Eine mathematische Definition von N beruht z.B. auf den Peano-Axiomen, mit
denen man N als die Menge definiert, die ein spezielles Element 1 enthält4 , und
die mit jedem n auch dessen Nachfolger n′ enthält. Addition, Multiplikation und
Größenvergleich lassen sich rekursiv basierend auf 1 und der Nachfolgerfunktion ′
definieren. Eine Umsetzung dieser Ideen auf einem Computer ist zwar prinzipiell
möglich, aber genauso dem Dilemma des endlichen Speicherplatzes ausgesetzt und
darüberhinaus wenig effizient.
Zum Rechnen auf Computern bietet sich die Basisdarstellung natürlicher
Zahlen an. Zu einer Basis B ≥ 2 kann jede natürliche Zahl z eindeutig als
z=
ω−1
X
zi B i
(6.1)
i=0
mit ω = ⌊logB (z)⌋ + 1 und 0 ≤ zi < B für alle i geschrieben werden. Fixieren
wir B, so ist z durch die Ziffern z0 , . . . , zω−1 (bzgl. B) charakterisiert, und wir
nennen zω−1 6= 0 die führende Ziffer. Ziffern werden oft auch Stellen genannt, die
Zahl ω beschreibt die Stellenanzahl von z, und für fixe Stellenzahl ω können wir
auf diese Art alle Zahlen 0 ≤ z < B ω darstellen.
Bevor wir uns mit den arithmetischen Grundoperationen beschäftigen, diskutieren wir, wie natürliche bzw. ganze Zahlen auf einem Computer dargestellt
werden. Diese werden – gemeinsam mit den in Abschnitt ?? vorgestellten Gleitkommazahlen – die Grundbausteine zum Aufbau komplizierterer mathematischer
Objekte darstellen.
Computerrepräsentation (Natürliche und ganze Zahlen fixer Länge). Für die interne Zahlendarstellung in einem Computer wird abhängig von der verwendeten
Hardware (dem Prozessor, auch Chip“ genannt) eine Wortlänge ω fixiert und das
”
Dualsystem verwendet, d.h. B = 2, um die Ziffern z0 , . . . , zω−1 zu speichern. Heutzutage gebräuchliche Wortlängen sind ω = 16 (32 oder auch 64), womit wir Zahlen
zwischen 0 und 216 −1 = 65535 (232 −1 ≈ 4.3 Milliarden bzw. 264 −1 ≈ 1.8·1019 ) –
jeweils zur Basis 10 im danach benannten Dezimalsystem – zur Verfügung haben. Die einzelnen Ziffern zi ∈ {0, 1} im Dualsystem werden Bits genannt und
in Speicherzellen abgelegt, die nur die Werte 0 und 1 annehmen können, was in
elektronischen Schaltelementen durch kein Strom“ und Strom“ repräsentierbar
”
”
4 In
manchen Anwendungen erweist es sich als praktisch, auch die Zahl 0 zu den natürlichen
Zahlen zu zählen, und wir schreiben N0 für die Menge der natürlichen Zahlen mit 0.
6. N und Z
65
ist. Ein Block von 8 Bits wird auch 1 Byte genannt, in Systemen mit Wortlänge
32 benötigt eine natürliche Zahl somit 4 Bytes Speicher.
Sollen auch negative Zahlen darstellbar sein, so verwendet man in der VorzeichenBetrag-Darstellung ein Bit für das Vorzeichen und die restlichen ω − 1 Bits für den
Betrag der Zahl. Mit ω = 16 können wir so Zahlen im Dezimalsystem zwischen
−215 − 1 = −32767 und 215 − 1 = 32767. In der Vorzeichen-Betrag-Darstellung
gibt es zwei Möglichkeiten, die Zahl 0 darzustellen, nämlich −0 und +0. Dies
ist in sogenannten B-Komplement-Darstellungen nicht der Fall, wo mathematisch
gesprochen jede negative Zahl −z durch B ω − z dargestellt wird. In der Zweierkomplementdarstellung ist dann jede Zahl mit führendem Bit 1 als negative Zahl
zu interpretieren. Hier besitzt 0 und auch jede andere Zahl eine eindeutige Darstellung, wodurch (im negativen Bereich) um eine Zahl mehr dargestellt werden
kann. Mit 16 Bits können wir damit Dezimalzahlen zwischen −32768 und 32767
darstellen.
y
Computerprogrammierung (N und Z in gängigen Programmiersprachen). Die meisten Programmiersprachen stellen Datenstrukturen für diese Fragmente von N
und Z zur Verfügung. In manchen Sprachen hat man die Wahlmöglichkeit zwischen langen (32 oder 64 Bits) und kurzen Zahlen (16 oder 32 Bits) bzw. zwischen vorzeichenlosen – d.h. natürlichen – Zahlen und solchen mit Vorzeichen –
also ganzen Zahlen. In der Praxis findet in gängigen Computerchips meist die
Zweierkomplement-Darstellung Anwendung.
Im internen Prozessor eines Computers wird also mit Basis 2 gearbeitet, wir
wollen in unseren weiteren Betrachtungen und Beispielen allerdings zur gewohnten
Basis 10 denken. Alle hier gewonnenen Erkenntnisse und Prinzipien lassen sich
leicht auf Darstellungen mit anderer Basis übertragen.
Beispiel (Zehnerkomplement-Darstellung). Im Dezimalsystem mit Wortlänge 4
können wir die natürlichen Zahlen von 0 bis 104 − 1 darstellen, also 0, . . . , 9999. In
Zehnerkomplement-Darstellung sind unter denselben Voraussetzungen die ganzen
Zahlen −5000, . . . , 4999 darstellbar, wobei das Vorzeichen nicht explizit abgespeichert wird. Zwischen 0 und 4999 bleibt alles unverändert, aber jede Zahl mit einer
führenden Ziffer 5, 6, 7, 8 oder 9 wird als negative Zahl gedeutet, etwa 5000 als
−5000, dann 5001 als −4999, bis hinauf zu 9999, das für die Zahl −1 steht.
y
Die aus der Schule bekannten Rechenabläufe zum Addieren, Subtrahieren,
Multiplizieren und Dividieren sind die klassischen Algorithmen für die Grundrechnenoperationen auf Zahlen in Basisdarstellung. In diesen Verfahren werden einfachste Operationen auf Ziffern als Elementaroperationen vorausgesetzt, nämlich
A das Addieren (Subtrahieren) zweier Ziffern resultierend in einer Ziffer und
einem Übertrag 0 oder 1,
M das Multiplizieren zweier Ziffern resultierend in einer zweistelligen Zahl und
D das Dividieren einer zweistelligen Zahl durch eine Ziffer, sofern der Quotient
und Rest jeweils Ziffern ergeben.
66
Kapitel II. Zahlbereiche
Wenn wir im Zehnersystem mit Papier und Bleistift größere Zahlen addieren, subtrahieren oder multiplizieren, so greifen wir auf einfache Berechnungen A und M
als Elemntaroperationen zurück, die wir im Kindesalter auswendig gelernt haben, das Einmaleins“. Auch am Computer kommen die klassischen Algorithmen
”
zum Addieren/Subtrahieren/Multiplizieren zweier ω-stelliger Zahlen zum Einsatz,
und auch hier basieren sie tatsächlich rein auf elementaren Operationen A und
M. Auf niedrigster Stufe sind A und M die Addition bzw. Multiplikation zweier
Bits, die in einfachsten Schaltkreisen umgesetzt werden können. Darauf aufbauend lassen sich etwas kompliziertere Schaltelemente zur 16-, 32- oder 64-Bit Addition/Multiplikation bauen. Die Division mit Rest einer 2ω-stelligen Zahl durch
eine ω-stellige ist etwas trickreicher, folgt aber auch in ihren wesentlichen Zügen
dem aus der Schule bekannten Algorithmus, der auf schrittweiser Division einer
(ω +1)-stelligen durch eine ω-stellige Zahl beruht. Für einen Algorithmus zu dieser
Problemstellung verweisen wir auf [Knu68], wir kommen auf den klassischen Divisionsalgorithmus auch im nachfolgenden Abschnitt noch genauer zu sprechen. Der
in Abschnitt 1 vorgestellte Algorithmus basierend auf fortgesetzter Subtraktion
findet hier keine Anwendung.
Computerprogrammierung (Arithmetik N und Z in gängigen Programmiersprachen). In jeder Programmiersprache können wir davon ausgehen, dass für die
vorhandenen Datenstrukturen für N bzw. Z die entsprechenden arithmetischen
Grundoperationen zur Verfügung stehen. Diese greifen üblicherweise direkt auf
die im Prozessor für fixe Wortlänge ω realisierten Operationen zurück. Die Länge
der Operanden und auch des Resultats ist dabei jeweils mit ω begrenzt, und bei
Addition und Multiplikation zweier ω-stelliger Zahlen kann es vorkommen, dass
das Resultat nicht mehr mit ω Stellen darstellbar ist. In diesen Fällen spricht man
von Überlauf (engl. overflow ), und es hängt von der konkreten Sprache ab, wie
Überlauf behandelt wird.
Zusätzlich zu A, M und D beruhen die klassischen Algorithmen nur auf Multiplikationen mit Potenzen der Basis, die aber nur einem Verschieben der Ziffern
entspricht und deswegen auch als Elementaroperation betrachtet werden kann.
Den Aufwand für die Grundoperationen beschreiben wir durch die Anzahl der notwendigen Bit-Operationen. Addition und Subtraktion benötigen O(ω), die Multiplikation O(ω 2 ) Ziffernoperationen und Verschiebungen. Die Komplexität der
Algorithmen hängt demnach rein von ω und nicht von den Inputs ab, bei fixem
Prozessor und damit fixer Wortlänge ist sie also konstant. Darüberhinaus sind die
Algorithmen in elektronischen Schaltkreisen in der Computer-Hardware enorm
effizient ausführbar.
Natürliche und ganze Zahlen beliebiger Länge
Für viele Anwendungen ist die oben beschriebene Darstellung bei weitem ausreichend, da ja z.B. bei 32 Bit immerhin ca. 4.3 Milliarden ganze Zahlen zur
Verfügung stehen. Andererseits zeigen viele Algorithmen das Phänomen, dass beim
6. N und Z
67
Rechnen mit ganzen Zahlen deren Größe rapide zunimmt, inbesondere gilt dies für
Zähler und Nenner beim Rechnen mit rationalen Zahlen, siehe Abschnitt 8, und
beim Rechnen mit Polynomen, siehe Abschnitt 14, sodass man hier schnell an die
Grenzen stößt, wenn man die Zahlen in ihrer Größe bzw. Stellenanzahl beschränkt.
Die Idee ganzer Zahlen beliebiger Länge ist nun, aufbauend auf ganzen Zahlen einer fixen Wortlänge ω eine Basisdarstellung mit B = 2ω−1 zu verwenden,
wobei die der Hardware zugrundeliegende Wortlänge ω = 16, ω = 32 oder ω = 64
Bits gewählt wird. Die Ziffern“ einer derartigen Darstellung sind dann (ω − 1)”
Bit-Zahlen, die in den oben erwähnten Standard-Datenstrukturen repräsentiert
werden können, für negative Zahlen wird aber lediglich die führende Ziffer negativ dargestellt. Im Unterschied zum Computerchip, in dem eine fixe Stellenanzahl
unerlässlich für die effektive Umsetzung der Algorithmen in elektronischen Bauteilen ist, wird nun aber die Anzahl der Ziffern nicht fixiert, sondern es werden
prinzipiell beliebig viele Ziffern zur Darstellung einer natürlichen oder ganzen Zahl
herangezogen. Zur mathematischen Beschreibung der Basisdarstellung einer Zahl
benötigen wir daher eine geeignete Möglichkeit, beliebig viele Objekte geordnet
zu einem neuen Objekt zusammenzufassen. Mengen von Ziffern scheiden für die
Darstellung beliebig großer Zahlen aufgrund des fehlenden Ordnungsbegriffs aus.
Neben Mengen setzen wir auch Tupel als elementare mathematische Objekte
voraus und stellen uns darunter eine geordnete Kollektion von endlich vielen Objekten vor. Als Grundoperation auf einem Tupel t betrachten wir die Bestimmung
der Länge |t| und den Zugriff ti (für 1 ≤ i ≤ |t| oder manchmal auch 0 ≤ i < |t|)
auf einzelne Elemente des Tupels. Wie Mengen sind Tupel nicht in ihrer Länge
fixiert, sie unterstützen strukturelle Operationen zum Einfügen und Löschen von
Elementen an bestimmten Positionen und zum Zusammenhängen zweier Tupel zu
einem längeren Tupel. Für jedes Tupel t bezeichnen wir mit ti:j (für 1 ≤ i ≤ j ≤ |t|
oder 0 ≤ i ≤ j < |t| das Tupel hti , . . ., tj i. Für i > j ist ti:j das leere Tupel hi. Zur
Tupelbildung steht in Anlehnung an die Mengenschreibweise htx | x = i, . . . , ji für
das Tupel htx→i , . . ., tx→j i und analog dazu htx | x ∈ Ii, sofern aus dem Zusammenhang klar ist, in welcher Reihenfolge der (endliche) Indexbereich I zu durchlaufen
ist5 . Für i > j und I = ∅ beschreiben beide Konstrukte das leere Tupel hi. Beispiele
dazu sind
3
2
k k = 1, . . . , 5 = h1, 4, 9, 16, 25i
n n ∈ {0, 2, 4} = h0, 8, 64i.
Zur Realisierung von Algorithmen nehmen wir an, dass die gewählte Programmiersprache Tupel mitsamt den eben eingeführten Grundoperationen zur Verfügung
stellt. In Mathematica stehen für Tupel Listen mit einer Unzahl von Listenoperationen bereit.
Mathematisch sind Tupel sehr eng verwandt mit Vektoren, siehe Kapitel III,
jedoch verbindet man mit dem Begriff Vektoren vor allem arithmetische Operationen wie Addition und Multiplikation, die uns dann zum Begriff eines Vektorraumes
5 Hier
steht tx für einen beliebigen Ausdruck mit freier Variable x und tx→y für den Ausdruck,
der entsteht, wenn y für x eingesetzt wird.
68
Kapitel II. Zahlbereiche
führen. Eher selten hingegen führt man auf Vektoren strukturelle Operationen aus
wie das Zusammenhängen zweier Vektoren der Länge drei zu einem Vektor der
Länge sechs. Die Begriffe Vektor und Tupel werden nicht immer streng voneinander unterschieden, auch wir wollen für Tupel der Länge n bestehend aus Elementen
von Typ K die für Vektoren gebräuchliche Schreibweise K n verwenden.
Definition (Zifferntupel für ganze Zahlen beliebiger Länge). Sei ω die Wortlänge
des zugrundeliegenden
Prozessors und B = 2ω−1 . Dann wird eine natürliche Zahl
Pl
i
n = i=0 zi B durch ihr Zifferntupel hz0 , . . ., zl i repräsentiert. Die Zahl 0 wird
durch hi dargestellt, für n 6= 0 gilt 0 ≤ zi < B = 2ω−1 für alle i und wir wählen
l so, dass Bl 6= 0 ist. In dieser Form ist die Darstellung eindeutig, wir nennen
sie die kanonische Form von n. Ist n kanonisch durch hz0 , . . ., zl i repräsentiert, so
ist hz0 , . . ., zl−1 , −zl i die kanonische Form von −n und wir schreiben L(n) für die
Länge von n. In obiger Darstellung ist L(n) = l + 1. Wir nennen diesen Bereich
ganze Zahlen beliebiger Länge, im Englischen wird meist von (arbitrarily) long
integers gesprochen6 .
Computerrepräsentation (Datenstrukturen). Zum Aufbau neuer mathematischer
Objekte werden Datenstrukturen herangezogen. Darunter wollen wir eine Möglichkeit
verstehen, Daten strukturiert zusammenzufassen und abzuspeichern. Für jede Datenstruktur brauchen wir einen Konstruktor, um aus den Einzelteilen ein neues
Objekt zusammenzubauen, und Selektoren, um auf die Einzelteile eines Objektes zugreifen zu können. Vom Standpunkt der Mathematik reichen Mengen und
Tupel aus, um damit neue Objekte zu definieren. Zur Umsetzung am Computer
empfiehlt es sich aber, die Objekte in voneinander unterscheidbare Datenstrukturen zu untergliedern, sodass wir zum Beispiel verschiedene Arten von Tupel
auseinanderhalten können. Beispiele dazu werden wir in Kürze sehen. Die meisten
Programmiersprachen erlauben die Definition eigener Strukturen, in objektorientierten Sprachen sind etwa Klassen das geeignete Mittel.
Computerrepräsentation (Datenstruktur Z für ganze Zahlen beliebiger Länge).
Für ganze Zahlen beliebiger Länge führen wir eine Datenstruktur Z ein, in der
wir das zugehörige Zifferntupel abspeichern. Den Konstruktor nennen wir dabei
ebenfalls Z, und als Selektor halten wir uns ziff zum Zugriff auf das Zifferntupel
zur Verfügung7 .
y
6 In [Knu69] wird die Bezeichnung multi-precision arithmetic verwendet, was in der deutschen Übersetzung zu mehrfachgenauer Rechnung und zu Zahlen mit erweiterter Genauigkeit
wird. Das erklärt sich dadurch, dass die dort beschriebenen Konzepte nicht auf ganze Zahlen
beschränkt sind, sondern sich im Prinzip auch auf (Gleit-)Kommazahlen anwenden lassen, die
wir in Abschnitt ?? behandeln. In dem für uns interessanten Fall von ganzen Zahlen verbirgt sich
jedoch hinter der Ziffernliste beliebiger Länge eine Ausdehnung des darstellbaren Bereichs und
weniger eine Erhöhung der Genauigkeit.
7 Als Schreibweise in mathematischen Algorithmen vereinbaren wir für Konstruktoren etwa
z ← Z(h. . .i), um ein Objekt z in der gewünschten Datenstruktur zu kreieren, alternativ dazu
verwenden wir Z(ziff ← h. . .i). Zweiteres ist insbesondere dann übersichtlich, wenn die Struktur
aus mehreren Komponenten besteht. Zum Zugriff auf die Daten kann der Selektor einfach auf
die Struktur angewendet werden, also z.B. ziff(z), um auf das Zifferntupel von z zuzugreifen.
6. N und Z
69
Beispiel. Mit Wortlänge ω = 32 stellt z = h67890, 12345, 54321i ∈ Z die Zahl
67890 + 12345 · 231 + 54321 · 262 = 250511396233504824035634
zur gewohnten Basis 10 dar. Deren Negatives ist h67890, 12345, −54321i, und
eine Rechtsverschiebung des Tupels zu h0, 67890, 12345, −54321i entspricht der
Multiplikation mit B = 231 . Bei einer Linksverschiebung des Zifferntupels zu
q = h12345, 54321i geht die niedrigste Ziffer r = z0 = 67890 verloren. Die daraus resultierenden q = 116653459255353 und r = 67890 entsprechen Quotient und
Rest bei Division von z durch B.
y
Wenden wir uns nun den klassischen Algorithmen für die arithmetischen
Grundoperationen auf Z zu. Diese lassen sich auf beliebig langen ganzen Zahlen
ohne wesentliche Modifikationen übertragen, wenn man sich als Basis der Zahlendarstellung nun B = 2ω−1 denkt. Die zugrunde liegenden Elementaroperationen A,
M und D können hier mittels der oben besprochenen Operationen auf ω-Bit-Zahlen
umgesetzt werden. Die meisten Programmiersprachen bieten Zahlen in mindestens
zwei verschiedenen Längen an. Seien etwa int und long die verfügbaren Datenstrukturen für 32-Bit und 64-Bit Integers, dann wählen wir B = 2ω−1 = 231
als Basis für eine long integer Arithmetik. D steht dann meist direkt durch eine
vorhandene Division für long durch int zur Verfügung, und M kann man durch
Konversion der int-Operanden in long und Berechnung eines long-Resultat realisieren. Für A nutzen wir aus, dass die Operanden kleiner als 231 sind, sodass deren
int-Addition keinen Überlauf produzieren kann. Das geforderte 31-Bit Resultat
und den Übertrag ermittelt man durch Division mit Rest durch 231 , was gegebenenfalls durch reines Verschieben der Bits in effizienter Weise erreicht werden
kann.
Die klassischen Algorithmen zur Addition und Multiplikation beruhen auf
Addieren und Multiplizieren von Ziffern als Elementaroperationen. Bei der Division mit Rest von a durch b hingegen werden schrittweise die Ziffern des Quotienten
durch Division einer (L(b) + 1)-stelligen Zahl durch die L(b)-stellige Zahl b berechnet. Eine solche Operation steht jedoch als Elementaroperation noch nicht zur
Verfügung. Interessanterweise lässt sich aber in jedem Divisionsschritt die gesuchte Ziffer des Quotienten durch Division mit Rest der aus den beiden führenden
Ziffern des Dividenden gebildeten 2-stelligen Zahl durch die führende Ziffer des
Divisors berechnen. Somit haben wir nun einen Divisionsalgorithmus, in dem wir
nur auf die zugrundeliegenden Elementaroperationen A, M und D zurückgreifen.
Für Details, die bei einer Realisierung der klassischen Algorithmen für beliebig
lange Zahlen zu beachten sind, verweisen wir wieder auf [Knu68]. Wir setzen von
nun an also Algorithmen QuotRestN (bzw. QuotRestZ) zur simultanen Berechnung
von Quotient und Rest, QuotN (bzw. QuotZ) zur Berechnung des Quotienten und
RestN (bzw. RestZ) zur Berechnung des Restes voraus.
Liegen nun zwei Zahlen a, b ∈ Z vor, so liefert a + b ein Ergebnis mit maximaler Länge max(L(a), L(b)) + 1 (anstelle eines Resultats plus Übertrag), und a · b
ergibt eine Zahl mit maximaler Länge L(a) + L(b). Auf diese Weise können durch
70
Kapitel II. Zahlbereiche
elementare Rechenoperationen beliebig große Zahlen erzeugt werden, und diese
können ohne eine konzeptionelle Einschränkung betreffend ihrer Größe am Rechner auch dargestellt werden. Praktisch gilt natürlich auch hier eine Beschränkung,
nämlich durch den auf einem Computer momentan verfügbaren Speicherplatz.
Computerprogrammierung. In Computeralgebra-Systemen wie Mathematica oder
Maple wird standardmäßig mit Integern beliebiger Länge gerechnet, in Matlab
sind sie über die Symbolic Toolbox ebenfalls verfügbar. Herkömmliche Programmiersprachen bieten jedoch keinen Grunddatentyp für Integer beliebiger Länge, allenfalls sind zusätzliche Programm-Bibliotheken erhältlich. Die fehlende Längenbeschränkung
hat zur Folge, dass die klassischen Algorithmen nicht mehr in elektronischen
Schaltkreisen – der Hardware – realisiert werden können, sondern dass sie in Form
von Computerprogrammen in Software umgesetzt werden müssen. Dies kann bei
der long integer Arithmetik zu (deutlich) längeren Rechenzeiten im Vergleich zu
direkt im Prozessor ablaufenden Berechnungen führen.
Auf Seite 66 haben wir für die klassischen Algorithmen auf Zahlen fixer
Wortlänge konstanten Aufwand an Bit-Operationen festgestellt. Für Zahlen beliebiger Länge beschreiben wir nun die Komplexität der arithmetischen Grundoperationen durch die benötigten Elementaroperationen auf ω-Bit-Zahlen. Dabei
ziehen wir die Länge der Operanden als Maß für die Größe der Eingaben heran.
Für die Addition benötigt man dann im Durchschnitt O(min(L(a), L(b))) Elementaroperationen. Für die Multiplikation benötigt der klassische Algorithmus
L(a) · L(b) elementare Multiplikationen und L(b) Additionen von Zahlen, deren
kürzere eine Länge L(a) aufweist, insgesamt O(L(a) · L(b)) Elementaroperationen.
Zur Division mit Rest von a durch b werden maximal O(L(b) · (L(a) − L(b) + 1))
elementare Operationen benötigt.
Wir wollen abschließend die Multiplikation zweier Zahlen a und b etwas genauer unter die Lupe nehmen. Sei nun max(L(a), L(b)) ≤ 2n. Wir zerlegen dazu
sowohl a als auch b in zwei Hälften“, genauer gesagt
”
b̄ := bn:L(b)−1 .
ã := a0:n−1
ā := an:L(a)−1
bzw.
b̃ := b0:n−1
Für das Produkt der beiden Zahlen gilt dann
a · b = (ã + B n ā) · (b̃ + B n b̄) = ãb̃ + B n ((ã + ā)(b̃ + b̄) − ãb̃ − āb̄) + B 2n āb̄,
und wir brauchen nur drei Produkte zweier jeweils maximal n-stelligen Zahlen
berechnen, nämlich ã· b̃, ā· b̄ und (ã+ā)(b̃+ b̄). Dies führt direkt auf einen rekursiven
Divide-and-Conquer-Algorithmus, den sogenannten Karatsuba8 Algorithmus zur
Multiplikation ganzer Zahlen. Um den Algorithmus in seinen Details etwas zu
vereinfachen, empfiehlt es sich, a und b am Beginn mit Nullen auf eine geeignete
Länge l = 2k aufzufüllen. Wir konzentrieren uns im Algorithmus MultZKaratsuba
auf den Spezialfall der Multiplikation strikt positiver Zahlen, die Behandlung des
Vorzeichens und Multiplikation mit 0 ist einfach und bleibt dem Leser überlassen.
8 Karatsuba,
Anatolii Alexeevich: 1937–, http://www.mi.ras.ru/~karatsuba/index e.html
71
6. N und Z
Algorithmus MultZKaratsuba: Karatsuba Algorithmus in Z
if max(L(a), L(b)) = 1
p←a∗b
else
k ← ⌈log2 (max(L(a), L(b)))⌉,
l1 ← 2k−1 , l2 ← 2k
a, b ← Fülle(a, 2k ), Fülle(b, 2k )
ã ← a0:l1−1 , ā ← al1:l2−1
b̃ ← b0:l1−1 , b̄ ← bl1:l2−1
p1 ← MultZKaratsuba(ã, b̃)
p2 ← MultZKaratsuba(ā, b̄)
p3 ← MultZKaratsuba(ã + ā, b̃ + b̄)
s1 ← Verschiebe(p3 − p1 − p2, l1)
s2 ← Verschiebe(p2, l2)
p ← p1 + s1 + s2
return p
Aufruf:
Eingabe:
mit:
Ausgabe:
mit:
MultZKaratsuba(a, b)
a, b ∈ Z
a, b > 0
p∈Z
p = a · b.
Verwendete Unteralgorithmen
Fülle(n, d) füllt n rechts mit 0 auf Gesamtlänge d auf.
Verschiebe(n, d) verschiebt die Ziffern
von n um d Stellen nach rechts und
füllt n mit 0 auf.
Computerprogrammierung. In einer konkreten Realisierung des Algorithmus ist
zu berücksichtigen, dass ã ā, b̃ und b̄ nicht notwendigerweise in kanonischer Form
sind. Dies ist vor allem dann relevant, wenn die Unteralgorithmen zum Addieren
und Subtrahieren die Operanden in kanonischer Form erwarten.
Mit dem Karatsuba Algorithmus führen wir die Multiplikation zweier maximal n-stelliger Zahlen auf drei Multiplikationen jeweils maximal n/2-stelliger
Zahlen, einige Additionen maximal n-stelliger Zahlen und einige Verschiebungen
der Ziffern um maximal n Stellen zurück. Der Aufwand für die Additionen und
Verschiebungen ist jeweils O(n), also durch c · n mit c ∈ R+ beschränkt. Eine
obere Schranke für den Gesamtaufwand M (n) zur Multiplikation zweier Zahlen
der Länge n ist demnach durch
M (n) = 3M (n/2) + c · n
(6.2)
gegeben. Eine Lösung M (n) dieser Rekurrenzgleichung ausgedrückt rein durch n
kann man z.B. in Mathematica durch den Befehl
In[1]:= RSolve[{M (n) == 3M (n) + cn, M (1) == 1}, M (n), n]
Log[n]
Out[1]= {{M (n) → (2c + 1)3 Log[2] − 2cn}}
finden. Dies besagt, dass die durchschnittliche Anzahl von Elementaroperationen
Log[n]
durch (2c + 1)3 Log[2] − 2cn beschränkt, die durchschnittliche Komplexität somit
Log[n]
O(3 Log[2] ) = O(nlog2 (3) ) = O(n1.585 )
ist. Der klassische Algorithmus benötigt im Vergleich O(n2 ) Elementaroperationen, jedoch zahlt sich der zusätzliche Aufwand für Additionen, Verschiebungen
72
Kapitel II. Zahlbereiche
und Rekursion erst für sehr lange Zahlen aus. Der Karatsuba Algorithmus ist
darüberhinaus ein Beispiel eines Verfahrens, das mit rekursiven Aufrufen sehr
leicht und elegant zu formulieren ist, eine Überführung in einen Schleifenalgorithmus jedoch nicht in naheliegender Weise ermöglicht.
Der Rechenaufwand für die arithmetischen Grundoperationen auf ganzen
Zahlen beliebiger Länge hängt also ganz wesentlich von der Größe der Operanden
ab. Viele Komplexitätsaussagen über Algorithmen auf anderen mathematischen
Datenstrukturen (Vektoren, Matrizen, Polynome, etc.) beruhen jedoch auf der vereinfachenden Annahme von konstantem Aufwand für elementare Arithmetik und
beschreiben daher den Aufwand lediglich durch die Anzahl von arithmetischen
Operationen. Die Größe der zu verarbeitenden Zahlen wird dabei vernachlässigt,
insbesondere auch das Phänomen, dass Zwischenergebnisse während der Abarbeitung der Algorithmen enorm anwachsen“ können, sodass solche Aspekte zusätzlich
”
zu einem theoretischen Komplexitätsresultat als Beurteilungskriterium für Algorithmen herangezogen werden sollten.
Von nun an werden wir in Algorithmen, die mit beliebig langen natürlichen
oder ganzen Zahlen rechnen, der Einfachheit halber auf einer bestehenden Arithmetik für Zahlen beliebiger Länge aufbauen, wie sie etwa in Mathematica oder der
Symbolic Toolbox in Matlab zur Verfügung stehen. Das bedeutet insbesondere,
dass wir Zahlen immer in der gewohnten Dezimalschreibweise anstelle eines Zifferntupels zur Basis 2w−1 anschreiben werden, d.h. für z = h67890, 12345, 54321i ∈ Z
werden wir wie gewohnt 250511396233504824035634 schreiben, und wir werden
immer Z verwenden, ohne auf konkrete Datenstrukturen für Z einzugehen. Die
bisher vorgestellten Algorithmen sollen lediglich veranschaulichen, was in Systemen wie Mathematica oder Matlab vorgeht, wenn mit derart großen Zahlen
gerechnet wird.
Der Euklidsche Algorithmus
Das Bestimmen des größten gemeinsamen Teilers (ggT) zweier Zahlen ist eine der
zentralen Problemstellungen in N bzw. Z. Auch in anderen Gebieten – z.B. beim
Rechnen mit Brüchen – werden wir dieser Fragestellung wieder begegnen. Wir
rekapitulieren zuerst einige grundlegende Begriffe, bevor wir uns einem Verfahren
zur ggT-Berechnung zuwenden.
Definition (Teilbarkeit in Z). Seien a, b, t ∈ Z. Die Zahl t teilt a genau dann, wenn
ein q ∈ Z existiert, sodass a = tq. Wir schreiben dafür t|a und nennen t einen
Teiler von a. Gilt t|a und t|b, so ist t ein gemeinsamer Teiler von a und b. Wir
vereinbaren T (a) := {t ∈ Z | t|a} und T (a, b) := {t ∈ Z | t|a ∧ t|b}.
Ist a 6= 0 oder b 6= 0, dann ist die Menge T (a, b) der gemeinsamen Teiler von a
und b endlich und hat daher ein größtes Element bzgl. der natürlichen Ordnung ≤.
Definition (ggT in Z). Seien a, b ∈ Z mit a 6= 0 oder b 6= 0. Wir nennen
ggT(a, b) := max T (a, b)
73
6. N und Z
den größten gemeinsamen Teiler von a und b. Weiters legen wir ggT(0, 0) := 0
fest.
Problemstellung
Gegeben:
Gesucht:
mit:
(ggT in Z).
a, b ∈ Z.
t ∈ N0
t = ggT(a, b).
Wegen ggT(a, b) = ggT(|a|, |b|) reicht es aus, die Problemstellung für m, n ∈ N0 zu
untersuchen. Ist hier wiederum eine der Eingabezahlen 0, so ist die jeweils andere
der ggT, somit bleiben als interessante Fälle nur a, b ∈ N übrig.
Existenz des ggT ist schon geklärt worden, die Eindeutigkeit des ggT folgt
aus der Eindeutigkeit des Maximums in der Definition. Das oben angeführte Argument zur Existenz des ggT ist konstruktiv : wir erhalten ggT(a, b), indem wir
die endlichen Mengen T (a) und T (b) etwa durch Primfaktorzerlegung von a bzw.
b berechnen und dann das Maximum der endlichen Menge T (a, b) = T (a) ∩ T (b)
ermitteln. Diese Methode ist jedoch für größere a und b sehr aufwändig, man
bedenke, dass die Sicherheit einiger Verschlüsselungsverfahren9 genau auf dem
großen Aufwand der Faktorisierung ganzer Zahlen beruht.
Der Schlüssel zu einem effizienten Algorithmus liegt in der einfachen Beobachtung, dass
• ein gemeinsamer Teiler von a und b auch ein Teiler von a ± b ist, und dass
• ein Teiler von b auch jedes Vielfache von b teilt.
Seien nun q und r Quotient und Rest bei Division von a durch b. Ein gemeinsamer
Teiler von a und b teilt auch b · q und daher auch r = a − b · q. Umgekehrt teilt
ein gemeinsamer Teiler von b und r = a − b · q auch a = r + b · q. Damit ist
T (a, b) = T (b, r) und letztlich auch
ggT(a, b) = ggT(b, r).
Diese rekursive Eigenschaft kann direkt in einen rekursiven Algorithmus zur Berechnung von ggT(a, b) umgesetzt werden, dessen Basisfall bei ggT(a, 0) = a erreicht ist. Es ist solange zu dividieren, bis als Rest bei der Division 0 auftritt,
der letzte in dieser Reihe auftretende Divisor ist der ggT von a und b. Die der
Reihe nach auftretenden Divisoren bilden eine streng monoton fallende Folge in
N0 , daher muss die Rekursion nach endlich vielen Schritten terminieren.
Computerprogrammierung. Die bei der ggT-Berechnung auftretende spezielle Form
der Rekursion, in der das Resultat des rekursiven Aufrufs nicht mehr weiterverwendet wird, heißt Endrekursion (engl. tail recursion). Diese sind besonders leicht
9 Die Sicherheit des RSA Algorithmus zur Verschlüsselung elektronischer Nachrichten beispielsweise beruht darauf, dass eine genügend große Zahl z = p · q ohne vorherige Kenntnis der
Primfaktoren p und q schwierig zu faktorisieren ist.
74
Kapitel II. Zahlbereiche
als Schleifen realisierbar, weil im Zuge der rekursiven Aufrufe kein Stack“ aufge”
baut werden muss, siehe dazu die Erläuterungen zum rekursiven Funktionsaufruf
auf Seite 25. Man erkennt Endrekursion daran, dass im Algorithmus nach dem
rekursiven Aufruf keine weitere Anweisung mehr auszuführen ist.
Der auf diese Weise entstehende Algorithmus heißt Euklidscher10 Algorithmus, den wir hier in Form einer Schleife präsentieren, siehe GGTZEuklid.
Algorithmus GGTZEuklid: Euklidscher Algorithmus für ganze Zahlen
t ← |a|, r ← |b|
while r 6= 0
s ← RestN(t, r), t ← r, r ← s
return t
Aufruf:
Eingabe:
Ausgabe:
mit:
GGTZEuklid(a, b)
a, b ∈ Z.
t ∈ N0
t = ggT(a, b).
Eine Komplexitätsuntersuchung des Euklidschen Algorithmus gestaltet sich
sehr aufwändig und auch mathematisch schwierig. Wir begnügen uns mit einer
Abschätzung, die auch die Größe des Resultats miteinbezieht, wonach der oben
beschriebene Algorithmus GGTZEuklid zur Berechnung von t = ggT(a, b) maximal O(min(L(a), L(b)) · (max(L(a), L(b)) − L(t) + 1)) elementare arithmetische
Operationen benötigt.
Beispiel. Für a und b wie im Beispiel zum Karatsuba Algorithmus liefert der
Aufruf GGTZEuklid(a, b) den ggT 1, wir nennen a und b in diesem Fall relativ
prim. Rufen wir nun GGTZEuklid(a, b) mit a = 250511396233504824035634 und
b = 116653459255353 auf, so lauten die der Reihe nach berechneten Reste
r(1) = 67890
r(2) = 59793
r(3) = 8097
r(4) = 3114
r(6) = 1245
r(7) = 624
r(8) = 621
r(9) = 3
r(5) = 1869
r(10) = 0,
somit ist ggT(a, b) = 3. Die Folge |a|, |b|, r(1) , . . . , r(10) wird auch Euklidsche Restfolge genannt.
Der hier gezeigte Algorithmus kann in verschiedenen Weisen verallgemeinert
werden, etwa kann er wegen
ggT(a, b, c) = ggT(a, ggT(b, c))
leicht zum Berechnen des ggT beliebig vieler Zahlen adaptiert werden. Eine Erweiterung, die neben dem ggT auch noch eine Darstellung des ggT als Linearkombination der Ausgangszahlen berechnet, werden wir im nachfolgenden Abschnitt
kennenlernen.
10 Euklid, von Alexandria: 325 v.Chr. – 265 v.Chr. Sein Hauptwerk sind Die Elemente, die
eine axiomatische Herangehensweise an die Geometrie darstellen. Darin enthalten sind auch die
Grundlagen der Zahlenthorie, wie Beispielsweise Teilbarkeit und ggT.
75
6. N und Z
Das Lösen von Gleichungen in Z
Gleichungen mit ganzzahligen Koeffizienten, in denen ganzzahlige Lösungen gesucht sind, heißen allgemein diophantische11 Gleichungen, etwa
x2 + y 2 = z 2
(6.3)
für gesuchte x, y, z ∈ Z. Geometrisch interpretiert sind hier ganze Zahlen gesucht,
die als Seitenlänge eines rechtwinkeligen Dreiecks auftreten können, wobei man
naturgemäß an positiven Lösungen interessiert ist. Die Gleichung (6.3) besitzt
unendlich viele Lösungen, genannt pythagoräische12 Tripel. Die Verallgemeinerung
von (6.3)
xn + y n = z n für n ∈ N
ist ebenfalls eine diophantische Gleichung, sie besitzt jedoch für n > 2 nach dem
großen Fermat’schen13 Satz keine Lösungen x, y, z ∈ Z. Wir wollen uns nun linearen diophantischen Gleichungen, das sind solche, die keine Potenzen von Unbekannten enthalten, zuwenden und hier insbesondere den Fall von Gleichungen
mit zwei Unbekannten studieren.
Problemstellung (Lineare diophantische Gleichung in zwei Unbekannten).
Gegeben: a, b, c ∈ Z.
Gesucht: x, y ∈ Z
mit: ax + by = c.
Für eine Untersuchung der Existenz von Lösungen einer diophantischen Gleichung bemerken wir zuerst, dass natürlich immer ggT(a, b)|(ax + by) gilt. Im Falle
der Lösbarkeit der diophantischen Gleichung muss damit auch ggT(a, b)|c gelten.
Sei nun umgekehrt ggT(a, b)|c erfüllt, also c = q · ggT(a, b). Falls die Gleichung
ax + by = ggT(a, b)
(6.4)
lösbar ist, d.h. ax′ + by ′ = ggT(a, b), dann ist mit
x = qx′
und y = qy ′
(6.5)
eine Lösung der ursprünglichen diophantischen Gleichung gefunden. Zur Lösung
von (6.4) studieren wir die vom Euklidschen Algorithmus berechnete Restfolge
|a|, |b|, r(1) , . . . , r(k) = ggT(a, b), 0.
Die ersten zwei Werte der Restfolge sind wegen |a| = a · sgn(a) + b · 0 und b =
a · 0 + b · sgn(b) trivial als Linearkombination von a und b darstellbar. Kann nun
11 Diophant,
von Alexandria: ca. 200 n.Chr.–280 n.Chr., griechischer Mathematiker.
von Samos: ca. 570 v.Chr.–475 v.Chr., griechischer Mathematiker und Phi-
12 Pythagoras,
losoph.
13 Fermat, Pierre de: 1601–1665.
76
Kapitel II. Zahlbereiche
sowohl r(i−2) als auch r(i−1) als Linearkombination von a und b dargestellt werden,
also
r(i−2) = ax(i−2) + by (i−2)
r(i−1) = ax(i−1) + by (i−1) ,
dann kann wegen
r(i) = r(i−2) − qr(i−1) = ax(i−2) + by (i−2) − q(ax(i−1) + by (i−1) )
= a(x(i−2) − qx(i−1) ) + b(y (i−2) − qy (i−1) ) (6.6)
auch r(i) als Linearkombination von a und b geschrieben werden. Wir können also
im Euklidschen Algorithmus zusätzlich Koeffizienten x und y wie in (6.6) beschrieben mitrechnen, mit denen beim Abbruch des Algorithmus eine Darstellung von
r(k) = ggT(a, b) als Linearkombination ax(k) + by (k) – und damit auch eine Lösung
von (6.4) – gegeben ist. Diese Variante des Verfahrens wird erweiterter Euklidscher
Algorithmus genannt.
Algorithmus ErwGGTZEuklid: Erweiterter Euklidscher Algorithmus in Z
t ← |a|, r ← |b|
x ← sgn(a), y1 ← sgn(b), y, x1 ← 0
while r 6= 0
q, s ← QuotRestN(t, r), t ← r, r ← s
x2 ← x − qx1, y2 ← y − qy1
x, y ← x1, y1, x1, y1 ← x2, y2
return t, x, y
Aufruf:
Eingabe:
Ausgabe:
mit:
ErwGGTZEuklid(a, b)
a, b ∈ Z.
t ∈ N0 , x, y ∈ Z
t = ggT(a, b) und
t = ax + by.
Beispiel. Mit a und b wie im Beispiel oben berechnet der erweiterte Euklidsche
Algorithmus eine Darstellung
a · 187291604932 + b · (−402205658999146152045) = 3
(6.7)
des ggT als Linearkombination der Ausgangswerte.
Satz (Lösbarkeit einer linearen diophantischen Gleichung). Seien a, b, c ∈ Z. Dann
gilt:
Die Gleichung ax + by = c ist lösbar für x, y ∈ Z ⇐⇒ ggT(a, b)|c.
Im Fall der Lösbarkeit existieren jedoch automatisch unendlich viele Lösungen,
da mit jeder Lösung x, y z.B. auch x + b und y − a eine Lösung der Gleichung darstellt. Zudem sind die Eingabe- und Ausgabevariablen in dieser Aufgabenstellung
keine reellen Zahlen, sodass jegliche Überlegungen hinsichtlich der Kondition das
Problems Lösen einer linearen diophantischen Gleichung“ hinfällig sind.
”
Die oben angestellten Überlegungen zur Existenz von Lösungen einer diophantischen Gleichung führen nun unmittelbar zu einem Lösungsverfahren basierend auf (6.5) und dem erweiterten Euklidschen Algorithmus.
77
7. Zm
Algorithmus LöseLinDiophant: Lösen einer linearen diophantischen Gleichung in
zwei Unbekannten
if a = b = c = 0
x, y ← 0
else
t, x′ , y ′ ← ErwGGTZEuklid(a, b)
q ← QuotZ(c, t)
x ← qx′ , y ← qy ′
return x, y
Aufruf:
Eingabe:
mit:
Ausgabe:
mit:
LöseLinDiophant(a, b, c)
a, b, c ∈ Z
ggT(a, b)|c.
x, y ∈ Z
ax + by = c.
Beispiel. Für eine Lösung der diophantischen Gleichung ax − by = −6 mit a und
b wie oben berechnet LöseLinDiophant(a, −b, −6) zuerst die Darstellung (6.7) für
ggT(a, −b) = 3. Da 3| − 6 hat die Gleichung Lösungen, eine davon erhalten wir
mit q = −2 aus (6.7) als x = −374583209864 und y = −804411317998292304090.
7 Zm
Bei der Darstellung ganzer Zahlen auf einem Computer haben wir Datenstrukturen
kennengelernt, mit denen etwa der Bereich zwischen 0 und 2ω − 1 darstellbar ist.
Beim Rechnen mit diesen Zahlen kann Überlauf auftreten, wenn das Resultat nicht
mehr im darstellbaren Bereich liegt, so ergibt etwa (2ω − 1) + 2 als Resultat 1.
Das korrekte Ergebnis 2ω + 1 stimmt mit 1 jedoch modulo 2ω überein, d.h. bei
Division durch 2ω haben 2ω + 1 und 1 gleichen Rest.
Mathematische Grundlagen
Aufbauend auf der Teilbarkeitsrelation auf Z können wir Kongruenz modulo m
definieren.
Definition (Kongruenz modulo n). Sei m ∈ N. Die Zahlen a, b ∈ Z heißen kongruent modulo m genau dann, wenn gilt: m|(a − b). Wir schreiben dafür a ≡m b.
Es lässt sich einfach nachrechnen, dass ≡m eine Kongruenzrelation auf Z
ist, d.h. eine Äquivalenzrelation auf Z, die mit Addition und Multiplikation auf Z
verträglich ist im Sinne von
a ≡m b
=⇒ (a + a′ ≡m b + b′ und a · a′ ≡m b · b′ ).
(7.8)
a′ ≡ m b ′
Definition (Kongruenzklassen, Rechnen modulo m). Die Äquivalenzklasse von a
bzgl. ≡m wird auch Restklasse von a modulo m genannt und mit [a]m bezeichnet.
Weiters ist
Zm := [a]m a ∈ Z ,
78
Kapitel II. Zahlbereiche
und in Zm heißt m der Modul. Auf Zm können durch
[a]m · [b]m := [a · b]m
[a]m + [b]m := [a + b]m
selbst wieder eine Addition und eine Multiplikation definiert werden, die wegen (7.8) wohldefiniert sind, d.h. die Resultate hängen nicht von den konkret
gewählten Repräsentanten der Klassen ab.
y
Beispiel. In Z3 lauten die Klassen
[0]3 := {. . . , −6, −3, 0, 3, 6, . . . }
[1]3 := {. . . , −5, −2, 1, 4, 7, . . . }
[2]3 := {. . . , −4, −1, 2, 5, 8, . . . }.
Wegen a ≡3 a + 3 existieren keine weiteren (von diesen verschiedene) Klassen, und
jede Klasse hat die Gestalt [a]3 = {a + k · 3 | k ∈ Z}. Addition und Multiplikation
verhalten sich laut Definition wie in den folgenden Verknüpfungstafeln gezeigt.
+
[0]3
[1]3
[2]3
[0]3
[0]3
[1]3
[2]3
[1]3
[1]3
[2]3
[0]3
·
[0]3
[1]3
[2]3
[2]3
[2]3
[0]3
[1]3
[0]3
[0]3
[0]3
[0]3
[1]3
[0]3
[1]3
[2]3
[2]3
[0]3
[2]3
[1]3
Das Rechnen mit Restklassen kann auch rein auf den Repräsentanten betrachtet
werden, weshalb die Klassenschreibweise oft weggelassen wird und etwa statt
[2]3 · [2]3 = [4]3 = [1]3
nur kurz
2·2 =1
(mod 3)
geschrieben wird14 .
y
Aus den Verknüpfungstafeln von Z3 sieht man sofort, dass jedes Element
außer [0]3 bzgl. der Multiplikation invertierbar ist. In Z4 hingegen ist [2]4 wegen
[2]4 · [1]4 = [2]4
[2]4 · [2]4 = [0]4
[2]4 · [3]4 = [2]4
nicht invertierbar bzgl. der Multiplikation. Wann ist nun eine Zahl b 6= 0 invertierbar modulo m, anders gefragt: wann hat die Gleichung bx = 1 (mod m) eine
Lösung? Nun ist aber
bx = 1 (mod m) ⇐⇒ bx − km = 1 ⇐⇒ ggT(b, m) · (b′ x − km′ ) = 1.
(7.9)
Daraus ist sofort abzulesen, dass b modulo m im Fall ggT(b, m) 6= 1 nicht invertierbar sein kann. Umgekehrt ist b modulo m im Fall ggT(b, m) = 1 invertierbar,
da dann die laut (7.9) gesuchten x und k mit bx − km = 1 durch den erweiterten
Euklidschen Algorithmus berechnet werden können.
14 Ein Zusatz wie (mod m)“ hinter einer Gleichheit zeigt an, dass es sich um eine Gleichheit
”
von Restklassen handelt, nicht um eine Gleichheit von Zahlen, oder anders gesagt, dass anstelle
von =“ eigentlich ≡m“ gemeint ist.
”
”
7. Zm
79
Satz (Restklassenring und -körper). Sei m ∈ N und m ≥ 2. Dann bildet Zm mit
+ und · einen Ring15 . Ist p prim, dann ist Zp mit + und · sogar ein Körper16 .
Darstellung am Computer
Allgemein lauten in Zm die Restklassen [a]m = {a+k·m | k ∈ Z}. Das Rechnen mit
Restklassen kann durch das Rechnen mit Repräsentanten der Klassen ersetzt werden, sofern aus jeder Klasse ein eindeutig bestimmter kanonischen Repräsentant
gewählt wird. Dies geschieht in der Regel durch einen sogenannten kanonischen
Simplifikator.
Computerrepräsentation (Datenstrukturen für Restklassen). Zm besteht aus m
Restklassen, die wir durch ihre kanonischen Repräsentanten darstellen.
1. Wählt man dabei aus jeder Restklasse den kleinsten nicht-negativen Wert
als kanonische Form, so ist {0, . . . , m − 1} die Menge der möglichen Repräsentanten, wir nennen diese Datenstruktur Z+
m . Der kanonische Simplifikator dazu lautet klarerweise RestZ(., m), d.h. die kanonische Form von a in
Z+
m wird als Rest bei Division von a durch m berechnet.
2. Als interessante Alternative dazu bietet es sich manchmal an, die m Rem
präsentanten als {−⌊ m−1
2 ⌋, . . . , 0, . . . , ⌊ 2 ⌋} möglichst symmetrisch um 0 anzuordnen, wir nennen diese Struktur nun Z±
m . Als kanonischen Simplifikator
hierfür verwendet man
(
RestZ(a, m)
falls RestZ(a, m) ≤ ⌊ m
2⌋.
kanonischZ±
(a)
:=
m
RestZ(a, m) − m sonst
Die Konstruktoren müssen durch Aufruf des jeweiligen Simplifikators dafür sorgen,
dass in den Datenstrukturen immer kanonische Repräsentanten verwendet werden.
Als Selektoren stellen wir in beiden Strukturen jeweils rep und mod zum Zugriff
auf den Repräsentanten und den Modul zur Verfügung.
y
Vereinbarung (Mathematische Objekte vs. Datenstrukturen). Prinzipiell wollen
wir ein mathematisch abstrakt definiertes Objekt – wie Zm – und seine konkreten
±
Computermodelle – wie Z+
m und Zm – auseinanderhalten. Stehen aber nun aber
für einen abstrakten Bereich D mehrere Datenstrukturen zur Realisierung bereit,
so wollen wir im algorithmischen Kontext die abstrakte Bezeichnung D auch als
Synonym für ein (beliebiges) Computermodell von D“ verwenden. Schreiben wir
”
also in einem Algorithmus gegeben z ∈ Z7“, so lassen wir offen, ob z in Z+
7 oder
”
±
Z7 repräsentiert sein soll. Schreiben wir hingegen gegeben z ∈ Z±
“,
so
deutet
7
”
15 Ein Ring ist ein Rechenbereich, in dem addiert, subtrahiert und multipliziert werden kann,
und wo alle gewohnten Rechengesetze wie Kommutativität, Assoziativität und Distributivität
gelten.
16 Ein Körper ist ein Ring, in dem zusätzlich durch jedes Element außer 0 dividiert werden
kann.
80
Kapitel II. Zahlbereiche
dies darauf hin, dass der entsprechende Algorithmus nur unter Verwendung der
angezeigten Datenstruktur funktioniert oder es zumindestens empfehlenswert ist,
das genannte Modell zu verwenden.
y
Gerechnet wird modulo m nun, indem mit Repräsentanten wie in Z gerechnet wird, und am Ende das Resultat in kanonische Form gebracht wird. Dies ist
zugleich ein allgemeines Rezept, wie man das Rechnen mit Äquivalenzklassen einer
Menge M durch das Rechnen mit Repräsentanten R ⊆ M und einen kanonischen
Simplifikator K realisieren kann: zu jeder Operation ◦M auf M kann die entsprechende Operation ◦R auf Repräsentanten der Klassen als
a ◦R b := K(a ◦M b)
definiert werden. In dieser Form kann das Rechnen mit Restklassen auch leicht
±
auf den eben eingeführten Datenstrukturen Z+
m oder Zm realisiert werden. Exemplarisch führen wir nun einen Algorithmus zum Multiplizieren in Z+
m an.
Algorithmus ·“: Restklassenmultiplikation
”
A ← rep(a), B ← rep(b)
Aufruf:
m ← mod(a)
Eingabe:
p ← Z+
Ausgabe:
m (A · B)
return p
mit:
a·b
a, b ∈ Z+
m
p ∈ Z+
m
p = a · b.
Computerprogrammierung (Polymorphismus). Unter Polymorphismus verstehen
wir die Möglichkeit, mehrere Definitionen für einen Funktionsnamen zuzulassen.
Im Beispiel der Restklassenmultiplikation tritt Polymorphismus in natürlicher
Weise auf, da wir ·“ sowohl für die Multiplikation von Restklassen als auch für
”
die Multiplikation in Z verwenden. Das Multiplizieren ganzer Zahlen ist selbstverständlich eine ganz andere Operation als das Multiplizieren von Klassen, wir
erlauben uns aber jeweils, von Multiplikation“ zu sprechen und dafür den Opera”
tor ·“ zu schreiben. Die Multiplikation ist damit polymorph, und wir sprechen vom
”
Überladen des Operators ·“. Nicht alle Sprachen unterstützen Polymorphismus,
”
im objektorientierten Programmieren jedoch ist es Standard und auch Mathematica erlaubt polymorphe Operationen.
In Zm kann jedes zu m relativ prime b bzgl. der Multiplikation invertiert
werden, in diesem Fall können wir also eine Division17 a durch b durchführen.
In Zp mit p prim ist das Dividieren somit durch alle b 6= 0 möglich. Wir haben
schon in (7.9) gesehen, dass für das gesuchte Inverse x zu b modulo m gelten muss
bx − km = 1. Gilt nun für b und m wie gefordert ggT(b, m) = 1, so berechnet
ErwGGTZEuklid(b, m) neben dem ggT genau die gesuchten Koeffizienten x und
−k.
17 Division
Rest.
nun im Sinne einer Umkehrung der Multiplikation, nicht im Sinne von Division mit
81
7. Zm
Algorithmus InversModEuklid: Restklasseninversion
B ← rep(b), m ← mod(b)
t, x, −k ← ErwGGTZEuklid(B, m)
x ← Z+
m (x)
return x
Aufruf:
Eingabe:
mit:
Ausgabe:
mit:
InversModEuklid(b)
b ∈ Z+
m
ggT(b, m) = 1
x ∈ Z+
m
b · x = 1 (mod m).
Beispiel. Für b = [871]7919 soll das multiplikative Inverse b−1 (mod 7919) berechnet werden. Dazu stellen wir b zuerst in einem Computermodell von Z7919 dar, etwa
durch b ← Z+
7919 (871). Ein Aufruf a ← InversModEuklid(b) liefert nun 7028 (in
Z+
),
zur
Kontrolle
ergibt a · b nach obigem Algorithmus tatsächlich 1 (in Z+
7919
7919 ).
Verwenden wir anstelle dessen das Modell Z±
,
so
ergibt
a
←
InversModEuklid(b)
7919
±
jetzt −891 (in Z±
7919 ) und a · b wieder 1 (in Z7919 ).
Systeme von Kongruenzen in Z
Wir wollen nun spezielle Systeme von Gleichungen in Restklassenbereichen betrachten, in denen z gesucht ist mit
z = r1
(mod m1 )
...
z = rm
(mod mn ).
(7.10)
Dieses Problem kann als Gleichungssystem für Restklassen“ angesehen werden,
”
jedoch ist in dieser Formulierung des Problems unklar, aus welchem Bereich das
gesuchte z stammen soll, da z als Restklasse bzgl. verschiedener Moduln mi beschrieben ist. Das System (7.10) kann aber auch als System von Kongruenzen
formuliert werden.
Problemstellung (Chinesisches Restproblem der Dimension n).
Gegeben: r, m ∈ Zn
mit: ggT(mi , mj ) = 1 für i 6= j.
Gesucht: z ∈ Z
mit: z ≡mi ri für i = 1, . . . , n.
Über die Lösbarkeit des chinesisches Restproblems gibt ein Satz Aufschluss,
der schon den alten Griechen und Chinesen bekannt war.
Satz (Chinesischer Restsatz). Seien r1 , . . . , rn , m1 , . . . , mn ∈ Z und die Moduln
mi paarweise relativ prim, d.h. ggT(mi , mj ) = 1 für i 6= j. Dann existiert ein
z ∈ Z mit
(7.11)
z ≡mi ri für i = 1, . . . , n.
Ist z eine Lösung von (7.11), dann ist auch z + k · m1 · . . . · mn für k ∈ Z eine
Lösung.
82
Kapitel II. Zahlbereiche
Der chinesische Restsatz garantiert uns die eindeutige Lösbarkeit des chinesisches Restproblems modulo m1 · . . . · mn , für einen Beweis des Satzes verweisen
wir jedoch auf [GCL93].
Für einen Lösungsalgorithmus des chinesischen Restproblems studieren wir
vorerst einmal den Spezialfall der Dimension 2. Sei also z eine Lösung der ersten
Kongruenz, d.h. z = m1 x + r1 . Soll z auch die zweite Kongruenz erfüllen, so muss
m1 x+r1 = m2 y+r2 sein, wir suchen also eine wegen ggT(m1 , m2 ) = 1 existierende
Lösung der diophantischen Gleichung m1 x − m2 y = r2 − r1 . Wir könnten nun zur
Lösung dieser Gleichung direkt LöseLinDiophant heranziehen, eine allgemeiner
anwendbare Methode erhalten wir jedoch, wenn wir den erweiterten Euklidschen
Algorithmus direkt einsetzen. Wir ermitteln erst ein c mit m1 c − m2 y ′ = 1, also
das Inverse vom m1 modulo m2 , berechnen daraus x = (r2 − r1 )c und letztlich das
gesuchte z = m1 x + r1 .
Algorithmus CRA2Z: Chinesischer Restalgorithmus für 2 Kongruenzen in Z
r1 ← rep(Z+
m1 (r1 ))
c ← InversModEuklid(Z+
m2 (m1 ))
+
x ← (Z+
m2 (r2 ) − Zm2 (r1 )) · c
z ← m1 · rep(x) + r1
return z
Aufruf:
Eingabe:
mit:
Ausgabe:
mit:
CRA2Z(r, m)
r, m ∈ Z2
ggT(m1 , m2 ) = 1.
z∈Z
z ≡m1 r1 und z ≡m2 r2
und 0 ≤ z < m1 m2 .
In CRA2Z kann als r1 die kanonische Form des gegebenen r1 in Zm1 herangezogen werden. Die Berechnung von x kann in Zm2 durchgeführt werden, da
jedes zu x modulo m2 kongruente x′ = km2 + x im Ergebnis auf
z ′ = m1 (km2 + x) + r1 = km1 m2 + (m1 x + r1 )
führt, sodass z ′ ≡m1 m2 z ist. Erst die letzte Berechnung von z ist in Z durchzuführen, sie ergibt zwangsläufig ein Resultat zwischen 0 und m1 m2 , das wir auch
als kanonische Form von z in Z+
m1 m2 betrachten können. In manchen Anwendungen ist man an einem Resultat in Z±
m1 m2 “ interessiert, was einfach zu erreichen
”
+
ist, indem die entsprechenden Rechnungen in Z±
m1 m2 statt in Zm1 m2 ausgeführt
werden.
Beispiel. Zur Berechnung einer ganzen Zahl z mit z ≡17 5 und z ≡31 12 berechnet
CRA2Z erst das Inverse von 17 in Z31 mittels erweitertem Euklidschen Algorithmus als c = 11. Damit wird x = (12 − 5) · 11 in Z31 berechnet, also x = 15, und
letztlich z = 17 · 15 + 5 = 260.
Nun wollen wir uns dem chinesischen Restproblems der Dimension n zuwenden, zu dessen Lösung wir wieder nach einer rekursiven Eigenschaft des Problems
suchen. Sei dazu r′ = CRA2Z(r1:2 , m1:2 ) eine Lösung der ersten beiden Kongru-
83
7. Zm
enzen, dann gilt
′
z ≡ m1 m2 r
z ≡mi ri für i = 3, . . . , n

 z ≡m1 r1
.
=⇒
z ≡m2 r2

z ≡mi ri für i = 3, . . . , n
(7.12)
Die rechte Seite in (7.12) ist das Originalproblem der Dimension n, die linke Seite
ist nun ein chinesisches Restproblem der Dimension n − 1, da unter den gegebenen
Voraussetzungen auch m1 m2 und mi (für i = 3, . . . , n) paarweise relativ prim sind.
Somit kann (7.12) als Grundlage für einen rekursiven Lösungsalgorithmus herangezogen werden, bei dem in jedem Rekursionsschritt die Dimension des Problems
abnimmt. Als Basisfall der Rekursion dient daher der Fall n = 2, für den wir ja
schon einen Lösungsalgorithmus haben. Dem oben vorgestellten CRA2Z kommt
dabei doppelte Bedeutung zu: zum Einen löst er den Basisfall, zum Anderen dient
er laut (7.12) auch der Dimensionsreduktion von n auf n − 1.
Algorithmus CRAZ: Chinesischer Restalgorithmus in Z
n ← |r|
if n = 2
z ← CRA2Z(r, m)
else
r2 ← CRA2Z(r1:2 , m1:2 )
m2 ← m1 m2
z ← CRAZ(r2:n , m2:n )
return z
Aufruf: CRAZ(r, m)
Eingabe: r, m ∈ Zn
mit: ggT(mi , mj ) = 1 für i 6= j,
n ≥ 2.
Ausgabe: z ∈ Z
mit: z ≡mi ri für i = 1, . . . , n
und 0 ≤ z < m1 · . . . · mn .
Computerprogrammierung. Dieser Algorithmus ist ein Beispiel für eine Rekursion, deren Ablauf auch sehr einfach in Form einer Schleife zu realisieren ist, da
das Resultat des rekursiven Aufrufs im Algorithmus nicht mehr weiterverarbeitet
wird – es stimmt in diesem Fall mit dem Endresultat überein. Solche Rekursionen
werden auch Tail Fällen entfällt der gesamte Aufbau des Stacks, und die Abarbeitung der Rekursion endet mit dem Erreichen des Basisfalls. Die zweite Phase –
das Abarbeiten des Stacks – entfällt ebenso. Im Beispiel des chinesischen Restalgorithmus können etwa in einer Schleife solange die ersten beiden Moduln durch
deren Produkt und die ersten beiden Reste durch die Lösung dieses chinesischen
Restproblems ersetzt werden, bis nur mehr je zwei Reste und Moduln verbleiben
und ein letzter Aufruf von CRA2Z die Lösung bringt.
Beispiel (Fortsetzung). Gesucht sei nun eine ganze Zahl z mit
z ≡17 5 z ≡31 12 z ≡23 11 z ≡28 16 z ≡41 21.
Zur Lösung dieser Aufgabe rufen wir CRAZ((5, 12, 11, 16, 21) , (17, 31, 23, 28, 41))
84
Kapitel II. Zahlbereiche
auf. Die Werte von r und m zeigen während der Rekursion den folgenden Verlauf:
r
m
(5, 12, 11, 16, 21) (17, 31, 23, 28, 41)
(260, 11, 16, 21)
(527, 23, 28, 41)
(11327, 16, 21)
(12121, 28, 41)
(120416, 21)
(339388, 41)
An dieser Stelle ist der Basisfall der Rekursion erreicht, und durch Anwendung
des chinsischen Restalgorithmus für Dimension 2 erhalten wir z = 2156744.
8 Q
Wir wollen uns nun den rationalen Zahlen Q und deren Verwendung am Computer zuwenden. Rationale Zahlen werden als Erweiterung der ganzen Zahlen eingeführt, da ganze Zahlen bzgl. der Multiplikation keine Inversen in Z besitzen
und daher keine Division ermöglichen. Die hier gezeigte Erweiterungskonstruktion, die von Z zu Q führt, kann aber nicht nur für ganze Zahlen durchgeführt werden, sie erlaubt allgemein die Erweiterung eines Integritätsbereichs18 R zu einem
(Quotienten-)Körper. Aus algorithmischer Sicht benötigt man jedoch in R auch
eine Division mit Rest, sodass größte gemeinsame Teiler mittels des Euklidschen
Algorithmus berechnet werden können.
Wir bilden dazu Paare von ganzen und betrachten die Relation
hz, ni ∼ hz ′ , n′ i :⇔ zn′ = nz ′ .
Durch einfaches Nachrechnen läßt sich eine wichtige Eigenschaft der Relation ∼
nachweisen.
Satz. Die Relation ∼ ist eine Äquivalenzrelation auf Z × (Z \ {0}).
Definition (Brüche und Brucharithmetik). Wir bezeichnen die Äquivalenzklasse
von hz, ni bezüglich ∼ mit nz und nennen jedes nz einen Bruch (über Z) mit z als
Zähler und n als Nenner. Die rationalen Zahlen sind dann definiert als
z z, n ∈ Z ∧ n 6= 0 .
Q :=
n
Auf Q definieren wir Addition und Multiplikation wie folgt:
z
zn′ + z ′ n
z′
+ ′ :=
n n
nn′
z z′
zz ′
.
· ′ :=
n n
nn′
(8.13)
y
18 Ein
Integritätsbereich ist ein kommutativer Ring mit Einselement ohne Nullteiler. Ein Nullteiler in R ist ein 0 6= a ∈ R, sodass für ein 0 6= b ∈ R gilt ab = 0.
85
8. Q
Wie immer, wenn Operationen auf Äquivalenzklassen definiert werden, ist darauf
zu achten, dass die so definierten Operationen wohldefiniert sind, siehe dazu auch
die Einführung von Restklassen auf Seite 77. In diesem Fall sei der Beweis, der
aus reinem Nachrechnen unter Zuhilfenahme der Definitionen besteht, dem Leser
überlassen. Das multiplikative Inverse zu nz ist nz , und jedes z ∈ Z können wir mit
dem Bruch z1 identifizieren, sodass man Q tatsächlich als eine Erweiterung von
Z betrachten kann. In dieser Erweiterung können wir nun ganze Zahlen z und n
dividieren, indem wir die Division z/n als
z n −1
z 1
= ·
·
1
1
1 n
in Q interpretieren. Nach obigen Rechenregeln erhält man als Resultat daher z/n =
z
n . Es lässt sich leicht zeigen, dass Q tatsächlich ein Körper ist.
Computerrepräsentation (Datenstruktur für Bruchzahlen). Für die Darstellung
von Brüchen am Computer haben wir bei unserer Behandlung von Restklassen
in Abschnitt 7 schon wertvolle Vorarbeiten geleistet. Wie Q besteht auch Zm aus
Äquivalenzklassen, und auch Brüche werden wir wie Restklassen am Computer
durch kanonische Repräsentanten darstellen. Wir führen dazu eine Datenstruktur
Q ein, in der wir mit zähler und nenner auf die beiden Komponenten eines Bruches
zugreifen. Zähler und Nenner sind dabei als beliebig lange ganze Zahlen in der Datenstruktur Z darzustellen. Auch dem Rechnen mit kanonischen Repräsentanten
sind wir auf Seite 80 schon begegnet, wir brauchen also nur noch einen kanonischen Simplifikator für Brüche. Dazu sei festgehalten, dass aus der Definition von
∼ für jedes t ∈ Z \ {0} sofort
z
t·z
=
n
t·n
folgt. Je nach dem, ob man diese Gleichheit von links nach rechts oder von rechts
nach links liest, heißt das, dass man Brüche mit ganzen Zahlen im Zähler und
Nenner erweitern oder gemeinsame Teiler im Zähler und Nenner kürzen kann. Als
kanonischen Repräsentanten der Äquivalenzklasse nz wählen wir dann ein Paar
hz ′ , n′ i so, dass z ′ und n′ relativ prim sind mit n′ > 0, d.h. als kanonischen
Simplifikator wählen wir
kanonischQ (hz, ni) := hQuotZ(z, t) · sgn(n), QuotZ(|n|, t)i
wobei t = ggT(z, n).
Auch hier wird man wieder den Konstruktor für die Datenstruktur so einrichten,
dass in Objekten des Typs Q immer kanonische Repräsentanten vorliegen. Auf
solchen Objekten definiert man nun die Grundoperationen
hz, ni ± hz ′ , n′ i := kanonischQ (hzn′ ± z ′ n, nn′ i)
hz, ni · hz ′ , n′ i := kanonischQ (hzz ′ , nn′ i)
hz, ni−1 := hn, zi
hz, ni/hz ′ , n′ i := hz, ni · hn′ , z ′ i.
y
86
Kapitel II. Zahlbereiche
Unter der Voraussetzung, dass die Operanden in kanonischer Form vorliegen,
lassen sich für die Addition und Multiplikation effizientere Algorithmen angeben
als die oben gezeigten Standardverfahren.
Satz. Seien z, n, z ′, n′ ∈ Z mit ggT(z, n) = ggT(z ′ , n′ ) = 1.
1. Seien weiters t = ggT(n, n′ ), N = QuotZ(n, t) und N ′ = QuotZ(n′ , t), dann
ist
ggT(zN ′ ± z ′ N, nN ′ ) = ggT(zN ′ ± z ′ N, t).
2. Seien t = ggT(z, n′ ), t′ = ggT(z ′ , n) und Z = QuotZ(z, t), N = QuotZ(n, t′ ),
Z ′ = QuotZ(z ′ , t′ ), N ′ = QuotZ(n′ , t), dann ist
ggT(ZZ ′ , N N ′ ) = 1.
Die nach ihrem Erfinder benannten Henrici19 -Algorithmen beruhen nun darauf, dass laut obigem Satz der ggT, der durch den kanonischen Simplifikator
aus Zähler und Nenner des Endresultats zu eliminieren ist, durch mehrere ggTBerechnungen mit kleineren Eingabezahlen ermittelt werden kann. Im Fall der
Addition ist ggT(n, n′ ) im Zähler und Nenner des Resultats jedenfalls ein gemeinsamer Faktor, den wir in einem ersten Schritt eliminieren. Teil 1 des Satzes sagt
uns, wie wir alle restlichen gemeinsamen Faktoren einfacher finden können. Im Fall
der Multiplikation sagt uns Teil 2 des Satzes, dass nach kreuzweisem Kürzen“ kei”
ne weiteren gemeinsamen Faktoren mehr enthalten sein können. Bedingung aber
ist jeweils, dass von kaninischen Brüchen als Input ausgegangen wird.
Algorithmus AddQHenrici: Addition von Brüchen
z ← zähler(a), n ← nenner(a)
z ′ ← zähler(b), n′ ← nenner(b)
t ← GGTZEuklid(n, n′ )
N ← QuotZ(n, t), N ′ ← QuotZ(n′ , t)
z ← z · N ′ + z′N , n ← n · N ′
t ← GGTZ(z, t)
zähler(s) ← QuotZ(z, t)
nenner(s) ← Quot(n, t)
return a
Aufruf:
Eingabe:
Ausgabe:
mit:
AddQHenrici(a, b)
a, b ∈ Q
s∈Q
s = a + b.
Computerprogrammierung. In den Henrici-Algorithmen weisen wir das Endresultat direkt dem Nenner und Zähler des Resultats zu, um zu verdeutlichen, dass
schon bekannt ist, dass es sich dabei um die kanonische Form handelt. Wir verwenden daher nicht den Konstruktor Q der Datenstruktur, da ansonsten unnötig
versucht wird, den Bruch in kanonische Form zu bringen.
19 Henrici,
Peter: ???
87
8. Q
Algorithmus MultQHenrici: Multiplikation von Brüchen
z ← zähler(a), n ← nenner(a)
z ′ ← zähler(b), n′ ← nenner(b)
t ← GGTZEuklid(z, n′ )
t′ ← GGTZEuklid(z ′ , n)
Z ← QuotZ(z, t), N ← QuotZ(n, t′ )
Z ′ ← QuotZ(z ′ , t′ ), N ′ ← QuotZ(n′ , t)
zähler(p) ← Z · Z ′
nenner(p) ← N · N ′
return p
Aufruf:
Eingabe:
Ausgabe:
mit:
MultQHenrici(a, b)
a, b ∈ Q
p∈Q
p = a · b.
Die Henrici Algorithmen bringen gegenüber den klassischen Algorithmen keine Verbesserung der asymptotischen Komplexität (gemessen in der Länge der Zahlen, die in die ggT-Berechnung eingehen), jedoch besitzen sie einen deutlich niedrigeren Proportionalitätsfaktor, was jedenfalls niedrigere Rechenzeiten zur Folge
hat, siehe Details dazu in [Win96].
Herunterladen