2.2 Binäraddierer mit Carry Look-Ahead

Ein Schaltkreis für binäre Addition

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 x,yN in Ihrer Binärschreibweise x=(xn1,,x2,x1,x0) und y=(yn1,,y2,y1,y0) gegeben und wollen die Summe s:=x+y berechnen bzw. ihre Binärdarstellung (sn,sn1,,s1,s0). Wir gehen hier davon aus, dass x und y beide mit n Bits repräsentiert sind (falls eine Zahl weniger Bits braucht, können wir sie immer mit führenden Nullen auffüllen). Die Summe s benötigt dann mindestens n+1 Bits. Bitte beachten Sie die unübliche "verkehrtrumme" Schreibweise (xn1,xn2,,x1,x0), die daher rührt, dass

x=i=0n1xi2i ,

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 xi,yi,ci, der die zwei Outputwerte si und ci+1 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 n-Bit-Zahlen hat O(n) Gates und O(n) 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 ci+1 zu berechnen, müssen wir zuerst ci kennen. Auch wenn wir uns jeden One-Bit-Adder als separaten Prozessor vorstellen, braucht der Algorithmus dennoch n 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 [a,b]:={a,a+1,,b} für 0abn1 und fragen uns, ob wir was wir über den Wert von cb+1 sagen können, wenn wir nur die Werte xb,xb1,,xa und yb,yb1,,ya kennen. Hier ein paar konkrete Beispiele für das Interval [a,b]=[5,8]:

An Stelle 7 entsteht auf jeden Fall ein Übertrag, egal was c7 ist. Es gilt also c8=1. Stelle 8 reicht dann den Übertrag weiter und somit ist c9=1, unabhängig von den Werten (x4,,x0) und (y4,,y0). 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 c9=0. Zuguterletzt:

Keine Stelle erzeugt aus eigener Kraft einen Übertrag, aber jede Stelle würde ihn weiterreichen, wenn denn einer hereinkäme. Daher gilt: c9=c5. 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 I={a,a+1,,b} ein Intervall natürlicher Zahlen. Die Werte pI=pI(x,y) und gI=gI(x,y) sind wie folgt definiert:
  • Wenn für alle iI das Paar xi,yi den Wert (0,1) oder (1,0) hat, dann ist pI=1 und gI=0.
  • Ansonsten sei i:=max{iI | (xi,yi){(0,0),(1,1)}}.
    • Falls (xi,yi)=(1,1), dann sind pI=gI=1.
    • Falls (xi,yi)=(0,0), dann sind pI=gI=0.

Insbesondere für ein-elementige Intervalle I=[a,a] gilt p[a]=xaya und g[a]=xaya. Es gilt gIpI.

Was nützt das uns nun? Beachten Sie, dass c0=0 immer gilt, und daher ci+1=g[0,i] gilt. Der Übertrag an Stelle i+1 ist genau dann 1, wenn das Interval [0,i] einen erzeugt. Wenn wir die g[0,i] also parallel berechnen können, dann auch die Summe sn,sn1,,s1,s0.

Carry generate und propagate parallel berechnen

Der Trick ist nun, dass wir gI und pI aus Teilintervallen zusammensetzen können. Sei a<i<b und I=[a,b], J=[a,i] und K=[i+1,b].

Wenn Interval K einen Übertrag erzeugt, dann erzeugt das Gesamtinterval I einen; wenn K verschluckt, dann verschluckt I; ansonsten (wenn K nur weiterreicht), dann tut I das, was J tut. Es gilt also

Beobachtung 2.2.3 Für a<b und aib sei I=[a,b], J=[a,i] und K=[i+1,b]. Dann gilt pI=gK(pKpJ) ,gI=gK(pKgJ) .

Wir können uns also einen schönen Generate-Propagate-Schaltkreis" bauen:

Wir nennen dieses Bauteil kurz ein gp-Gate. Auch fassen wir die zwei Werte gI und pI zu einem Paar zusammen: gpI:=(gI,pI). Wenn nun n=2d eine Zweierpotenz ist, dann können wir einen vollständigen Binärbaum aus gp-Gates bauen:

Die Intervalle, die in einem solchen Baum vorkommen, nenn wir Binärintervalle. Es sind Intervalle der Form [a,b], wobei a und b die d-Bit-Binärdarstellungen

(a)2=(ad1ad2ak 0 0  0k viele)(b)2=(ad1ad2ak 1 1  1k viele)

haben. Es gibt 2n1 solche Binärintervalle, und so viele Knoten hat auch der obige Baum. Jedes gp[i] können wir mit 2 Gates und Tiefe 1 berechnen; jedes gp-Gate braucht 4 Gates und hat Tiefe 2. Das ergibt für n=2d eine Tiefe von 1+2d=1+2logn und insgesamt 6n4 Gates.

Beobachtung 2.2.4 Die obige Konstruktion resultiert in einem Schaltkreis BI, der 2n Bits xn1,,x0,yn1,,y0 als Input nimmt und 2n1 Ouput-Gates hat, nämlich für jedes Binärinterval I eines, das gpI ausgibt. Der Schaltkreis BI hat 6n4 Gates und Tiefe 1+2logn

Jetzt muss man sich nur noch überlegen, wie man parallel alle pgI für alle Präfixintervalle I=[0,b].

Präfixintervalle [0,b]. Wir konstruieren nun einen Schaltpreis PI, der gpI für alle Präfixintervalle berechnet. Er hat n Outputs (jede eines für [0,0],[0,1],[0,2],,[0,n1]) und hat 2n1 Inputs, je eines für jedes Binärinterval K. Die Konstruktion wird einfacher, wenn wir statt dem geschlossenen Interval [0,b] das halboffene Interval [0,b):=[0,b1] betrachten. Wir müssen nun also gp[0,b) berechnen für b=1,2,,n. Wenn b eine Zweierpotenz ist, dann ist [0,b) ein Binärinterval, wir können also den entsprechenden Input gleich als Output durchleiten. Das eliminiert auch den Fall b=n=2d und wir müssen uns nur Gedanken machen über Werte 1bn1. Da b<2d gilt, hat b eine Binärdarstellung mit d Bits. Wegen b1 hat diese mindestens eine 1. Wir fokussieren uns auf die am weitesten rechts stehende 1:

b=(bn1bn2bk+1 1 0k)2

wobei 0k eine Folge von k Nullen ist (und nicht Null hoch k). Wir schreiben c=bn1bn2bk+1 und zerlegen I=[0,b) wie folgt:

I=[0,b)=[0d,c 1 0k)(1)=[0d,c 0 0k)[c 0 0k,c 1 0k)=:[0,b)K (2)=:IK .

Hier zeigt sich der Vorteil der halboffenen Intervalle: für abc gilt einfach [a,c)=[a,b)[b,c), ohne unangenehmes +1 irgendwo. Das zweite Interval in (1) ist [c 0 0k,c 1 0k)=[c 0 0k,c 0 1k], 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 gpI mit einem zusätzlichen gp-Gate aus gpI und gpK berechnen. Für gpI verfahren wir rekursiv. Um abzuschätzen, wie tief diese Rekursion geht, zählen wir die Anzahl der Einsen in der Binärdarstellung von b. In b ist diese maximal d, und in b ist sie eins weniger als in b; nach maximal d1 Rekursionsschritten sind wir also bei einem Interval [0,b) angelegt, wo die Binärdarstellung von b eine einzige 1 hat. Die Zahl b ist also eine Zweierpotenz und [0,b) somit ein Binärinterval, und wir haben gp[0,b) bereits vorliegen. Wir können gpI also mit maximal d1 hintereinander geschalteten gp-Gates berechnen. Jedes einzelne gp-Gate hat Tiefe 2, und daher erhalten wir:

Beobachtung 2.2.5 Der Schaltkreis PI hat Tiefe 2(d1)=2log(n)2.

Wieviele Gates hat dieser Schaltkreis? Wenn wir für jedes 1bn1 die Konstruktion parallel durchführen und mit |b|1 die Anzahl der Einsen in der Binärdarstellung von b schreiben, dann brauchen wir

b=1n1(|b|11)b=1n1(d1)=(d1)(n1)nlogn .

viele gp-Gates. In der Realität hat nicht jedes b genau d viele Einsen, daher ist der tatsächliche Wert der Summe etwas kleiner. Aber nicht viel:

Übungsaufgabe 2.2.2 Sei n=2d. Berechnen Sie b=1n1|b|1 , also die Gesamtzahl der Einsen in den Binärdarstellungen aller Zahlen 1bn1.

Fundamental besser wird unsere Konstruktion, wenn wir betrachten, dass wir zum Beispiel gpI und gpI nicht separat berechnen müssen, sondern den Outputwert gpI in der Berechnung von gpI wiederverwenden können. Anders gesagt: jedes gp-Gate in PI, mit dem wir gpI und gpK zu gpI kombinieren, ist gleichzeitig ein Output-Gate, nämlich für das Präfixinterval I. Unser Schaltkreis hat n Output-Gates gp[0,b). Für b=1,2,4,8,,2d können wir einfach das Input-Gate durchschalten, brauchen also nur nd1 zusätzliche Output-Gates. Jedes gp-Gate in PI entspricht so einem zusätzlichen Output-Gate, und somit hat PI insgesamt nd1 viele gp-Gates. Der Einfachheit halber: höchstens n. Für n=16 schaut das so aus:

Beobachtung 2.2.6 Der Schaltkreis PI hat Tiefe 2(d1) und besteht aus höchstens n vielen gp-Gates, also maximal 4n Gates.

Wir komibnieren nun BI und PI und erhalten somit einen Schaltkreis der Tiefe 1+2d+2(d1)=4d1 und Größe 6n4+4n=10n4, der alle gp[0,b] berechnet. Wir haben nun also alle c1,c2,,cn und können in einem finalen Schritt

si=xiyici

berechnen. Hierfür berechnen wir erst xy:

was vier Gates braucht, aber nur zwei neue, weil wir xiyi=g[i,i] und xiyi=p[i,i] bereits berechnet haben. Nun berechnen wir si als (xiyi)ci:

was vier weitere Gates braucht. Pro si brauchen wir also sechs weitere Gates. Der gesamte Schaltkreis hat somit 16n4 Gates. Was ist seine Tiefe? Der längste Pfad von si zurück zu einem Input geht durch ci und hat Tiefe 2 plus die Tiefe von ci, welche, wie oben beobachtet, 4d1 ist.

Theorem 2.2.7 Sei n=2d. Der gerade konstrukierte Schaltkreis für die Addition zweier n-Bit-Binärzahlen hat Tiefe 4log(n)+1 und Größe 16n4.