Dieses Teilkapitel finden Sie, in ausführlicherer Darstellung, auch als
Kapitel 1.3 in Theoretische
Informatik II.
Das Problem der Addition zweier Binärzahlen ist wie folgt:
Wir haben zwei Zahlen in Ihrer Binärschreibweise
und
gegeben und wollen die Summe
berechnen bzw. ihre Binärdarstellung
. Wir gehen hier davon aus, dass und
beide mit Bits repräsentiert sind (falls eine Zahl weniger Bits braucht, können wir sie
immer mit führenden Nullen auffüllen). Die Summe benötigt dann mindestens
Bits. Bitte beachten Sie die unübliche "verkehrtrumme" Schreibweise
, die daher rührt, dass
wir aber das most significant bit links schreiben. Binäraddition geht
wie Dezimaladdition, nur einfacher. Hier ein Beispiel:
Mit etwas mehr Notation sieht das dann so aus:
Wir brauchen also einen Schaltkreis mit drei Inputs
, der die zwei Outputwerte und berechnet:
Dann können wir diese Schaltkreise hintereinander schalten
und erhalten den sogenannten Ripple-Through-Adder.
Beobachtung 2.2.1 Ein Ripple-Through-Adder für -Bit-Zahlen
hat
Gates und Tiefe.
Übungsaufgabe 2.2.1
Implementieren Sie den Schaltkreis oneBitAdder. Versuchen Sie,
so wenig Gates (AND, OR, NOT) wie möglich zu verwenden.
Der Ripple-Through-Adder ist ein sequentieller Algorithmus: um
zu berechnen, müssen wir zuerst kennen. Auch wenn wir
uns jeden One-Bit-Adder als separaten Prozessor vorstellen, braucht
der Algorithmus dennoch Zeitschritte. Es findet also
gar keine Parallelisierung statt.
Carry-Lookahead: eine effiziente Parallelisierung
Effizientere Lösungen beginnen oft mit einer guten Definition. Wir betrachten ein Interval
für und fragen uns, ob wir
was wir über den Wert von sagen können, wenn wir nur die Werte
und kennen. Hier ein
paar konkrete Beispiele für das Interval :
An Stelle 7 entsteht auf jeden Fall ein Übertrag, egal was ist. Es gilt
also . Stelle 8 reicht dann den Übertrag weiter und somit ist ,
unabhängig von den Werten und .
Ein weiteres Beispiel:
An Stelle 5 wird ein Übertrag erzeugt (unabhängig der weiter rechts
stehenden Werte) und Stelle 6 reicht ihn weiter; an Stelle 7 wird
er jedoch "verschluckt", und auch Stelle 8 erzeugt nicht
aus eigener Kraft einen neuen Übertrag. Daher gilt .
Zuguterletzt:
Keine Stelle erzeugt aus eigener Kraft einen Übertrag, aber jede Stelle würde ihn weiterreichen,
wenn denn einer hereinkäme. Daher gilt: .
Ein Intervall kann also im Prinzip drei Dinge tun: (1) einen Übertrag erzeugen, in welchem
Fall wir von einem Carry generate sprechen; (2) einen Übertrag nicht erzeugen, aber
zumindest weiterreichen; (3) einen Übertrag verschlucken verschlucken.
Wenn (1) der Fall ist, sprechen wir von Carry generate. Wenn
(1) oder (2) der Fall ist, von Carry propagate.
Wir fassen zusammen und formalisieren:
Beobachtung / Definition (Carry propagate und Carry generate für
Intervalle) 2.2.2
Sei ein Intervall natürlicher Zahlen. Die Werte
und sind wie folgt definiert:
Wenn für alle das Paar den Wert oder
hat,
dann ist und .
Ansonsten sei .
Falls , dann sind .
Falls , dann sind .
Insbesondere für ein-elementige Intervalle gilt
und . Es gilt
.
Was nützt das uns nun? Beachten Sie, dass immer gilt, und daher
gilt. Der Übertrag an Stelle ist genau dann 1,
wenn das Interval einen erzeugt.
Wenn wir die also parallel berechnen können, dann
auch die Summe .
Carry generate und propagate parallel berechnen
Der Trick ist nun, dass wir und aus Teilintervallen zusammensetzen können.
Sei und , und .
Wenn Interval einen Übertrag erzeugt, dann erzeugt das Gesamtinterval einen;
wenn verschluckt, dann verschluckt ; ansonsten (wenn nur weiterreicht), dann
tut das, was tut. Es gilt also
Beobachtung 2.2.3
Für und sei , und .
Dann gilt
Wir können uns also einen schönen Generate-Propagate-Schaltkreis" bauen:
Wir nennen dieses Bauteil kurz ein -Gate. Auch fassen wir
die zwei Werte und zu einem Paar zusammen:
.
Wenn nun eine Zweierpotenz ist, dann können wir
einen vollständigen Binärbaum aus -Gates bauen:
Die Intervalle, die in einem solchen Baum vorkommen, nenn wir Binärintervalle.
Es sind Intervalle der Form , wobei und die -Bit-Binärdarstellungen
haben. Es gibt solche Binärintervalle, und so viele Knoten hat auch der obige Baum.
Jedes
können wir mit Gates und Tiefe 1 berechnen;
jedes -Gate braucht 4 Gates und hat Tiefe 2. Das ergibt für
eine Tiefe von und insgesamt Gates.
Beobachtung 2.2.4 Die obige Konstruktion resultiert
in einem Schaltkreis BI, der Bits als
Input nimmt und Ouput-Gates hat, nämlich für jedes Binärinterval eines,
das ausgibt. Der Schaltkreis BI hat Gates und Tiefe
Jetzt muss man sich nur noch überlegen, wie man parallel alle für alle
Präfixintervalle.
Präfixintervalle . Wir konstruieren nun einen Schaltpreis
PI, der für alle Präfixintervalle berechnet. Er hat Outputs
(jede eines für ) und hat Inputs,
je eines für jedes Binärinterval .
Die Konstruktion wird einfacher, wenn wir statt dem geschlossenen Interval das
halboffene Interval betrachten.
Wir müssen nun also berechnen für .
Wenn eine Zweierpotenz ist, dann ist ein Binärinterval, wir können also den
entsprechenden Input gleich als Output durchleiten.
Das eliminiert auch den Fall und wir müssen uns nur Gedanken
machen über Werte .
Da gilt, hat eine Binärdarstellung mit Bits. Wegen hat diese
mindestens eine . Wir fokussieren uns auf die am weitesten rechts stehende 1:
wobei eine Folge von Nullen ist (und nicht Null hoch ).
Wir schreiben und zerlegen
wie folgt:
Hier zeigt sich der Vorteil der halboffenen Intervalle: für
gilt einfach , ohne unangenehmes irgendwo.
Das zweite Interval in ist
,
wenn wir es wieder als geschlossenes Interval schreiben. Wir sehen: es ist ein
Binärinterval und steht dem Schaltkreis PI bereits als Input zur Verfügung.
Wir können nun mit einem zusätzlichen -Gate aus und berechnen.
Für verfahren wir rekursiv.
Um abzuschätzen, wie tief diese Rekursion geht, zählen wir die Anzahl der Einsen
in der Binärdarstellung von . In ist diese maximal , und
in ist sie eins weniger als in ; nach maximal Rekursionsschritten
sind wir also bei einem Interval angelegt, wo die Binärdarstellung von
eine einzige hat. Die Zahl ist also eine Zweierpotenz und somit
ein Binärinterval, und wir haben bereits vorliegen.
Wir können also mit maximal hintereinander geschalteten -Gates berechnen.
Jedes einzelne -Gate hat Tiefe 2, und daher erhalten wir:
Beobachtung 2.2.5 Der Schaltkreis PI hat
Tiefe .
Wieviele Gates hat dieser Schaltkreis? Wenn wir für jedes
die Konstruktion parallel durchführen und mit die Anzahl der Einsen in
der Binärdarstellung von schreiben, dann brauchen wir
viele -Gates. In der Realität hat nicht jedes genau viele Einsen, daher
ist der tatsächliche Wert der Summe etwas kleiner. Aber nicht viel:
Übungsaufgabe 2.2.2
Sei . Berechnen Sie
also die Gesamtzahl der Einsen in den Binärdarstellungen aller Zahlen .
Fundamental besser wird unsere Konstruktion, wenn wir betrachten, dass wir
zum Beispiel und nicht separat berechnen müssen, sondern
den Outputwert in der Berechnung von wiederverwenden können.
Anders gesagt: jedes -Gate in PI, mit dem wir und zu
kombinieren, ist gleichzeitig ein Output-Gate, nämlich für das Präfixinterval .
Unser Schaltkreis hat Output-Gates . Für
können wir einfach das Input-Gate durchschalten, brauchen also nur
zusätzliche Output-Gates. Jedes -Gate in PI entspricht so einem
zusätzlichen Output-Gate, und somit hat PI insgesamt viele -Gates.
Der Einfachheit halber: höchstens . Für schaut das so aus:
Beobachtung 2.2.6 Der Schaltkreis PI hat
Tiefe und besteht
aus höchstens vielen -Gates, also maximal Gates.
Wir komibnieren nun BI und PI und erhalten somit einen Schaltkreis
der Tiefe und Größe , der
alle berechnet. Wir haben nun also alle
und können in einem finalen Schritt
berechnen. Hierfür berechnen wir erst :
was vier Gates braucht, aber nur zwei neue, weil wir
und bereits berechnet haben. Nun
berechnen wir als :
was vier weitere Gates braucht. Pro brauchen wir also sechs weitere Gates.
Der gesamte Schaltkreis hat somit Gates. Was ist seine Tiefe? Der längste Pfad von
zurück zu einem
Input geht durch und hat Tiefe 2 plus die Tiefe von , welche,
wie oben beobachtet, ist.
Theorem 2.2.7 Sei . Der gerade konstrukierte
Schaltkreis für die Addition zweier -Bit-Binärzahlen hat
Tiefe und Größe .