Betrachtet wird hier nur die Ganzzahldivision.
Bei der Ganzzahldivision gilt folgende Regel der Bitbreiten:
Dividend / Divisor = Quotient und Rest |
---|
m bit / n bit = (m-n) bit Rest n bit |
Der unscheinbare (oder lästige) Rest ist
übrigens oft sehr nützlich und fällt stets als Nebenprodukt mit an!
Hochsprachen verdecken (=verschenken!) die innewohnende Eigenschaft der
Bitbreiten-Veränderung und des gleichzeitig anfallenden Divisionsrestes.
Es wird stets abgerundet (zur Null hin); zum Aufrunden vergleiche man den doppelten Rest mit dem Divisor, oder addiere vorher den halben Divisor auf den Dividenden.
Eine direkte Verarbeitung von Zweierkomplementzahlen ist unzweckmäßig und deshalb selten implementiert; deshalb vorher in Vorzeichen+Betrag umrechnen!
Hinweis (Moritz Strübe): Moderne Compiler können durch Optimierung:
Tipp: Bei der Division durch zu kleine Zahlen oder Null bekommt man als
Ergebnis die größte darstellbare Zahl, bei allen Programmier-Varianten.
Schutzverletzungen wie beim Mikroprozessor üblich muss man m. W. nicht
beachten.
Die Überlaufsituation ist gegeben, wenn die oberen n bit
des Dividenden größer oder gleich den
n bit des Divisors ist.
Diese werden durch Rechtsschieben erledigt! — 1x Rechtsschieben = Division durch 2.
Dabei gibt es üblicherweise zwei Rechtsschiebebefehle, für
vorzeichenlose und Zweierkomplement-Zahlen, sowie
einen Rotationsbefehl für niederwertige Bytes. Begonnen wird,
wie bei der schriftlichen Division, mit dem höchstwertigen Byte!
µC | höchstwertiges Byte/Word | niedere Bytes/Words | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Zweierkomplement | vorzeichenlos | alle Formate | |||||||||||||
8051 | mov C,ACC.7 rrc a |
Bei Potenzen von Zwei müssen die o.g. Befehle in einer Schleife ausgeführt werden.
Beachte: Alle, auch negative Zweierkomplementzahlen,
werden stets abgerundet!
Als Konsequenz erreicht man bei negativen Zahlen niemals Null, sondern
maximal -1 (=0FFh als Byte gesehen).
Als Rest gilt das zuletzt herausgeschobene Bit.
Die Lösung dazu ist derartig trivial, dass sie oft nicht für voll genommen wird: Es wird byteweise „uminterpretiert“, bei gleich bleibender Bitbreite muss vorn ein Byte hinzugesetzt werden. Dieses Byte ist bei vorzeichenlosen Zahlen stets Null. Bei Zweierkomplement muss bei negativen Zahlen 0FFh aufgefüllt werden!
µC | Neues höchstwertiges Byte/Word bei Zweierkomplement | |||||||
---|---|---|---|---|---|---|---|---|
8051 | mov C,ACC.7 ;a=altes MSB subb a,ACC ;neues MSB |
Beachte: Alle, auch negative Zweierkomplementzahlen,
werden stets abgerundet!
Als Rest n bit gelten die „verworfenen“ Bytes.
Bisweilen ist ein Messwert o. ä. durch eine Skalierungskonstante zu dividieren. Dann ist es oftmals besser, mit einem 2nfachen Kehrwert der Konstante zu multiplizieren und anschließend durch Rechtsschieben den Wert zu erhalten! Bei n=8 (oder =16) entfällt sogar das lästige Schieben.
Merke: Multiplizieren ist leichter als Dividieren!
Dieser Fall erfordert ggf. das Umwandeln einer Zweierkomplement-Zahl
in eine Vorzeichen-Betrags-Darstellung.
Voraussetzung für die Anwendbarkeit des eingebauten Befehls ist seine
ausreichende Bitbreite:
µC | Verfügbarer Divisionsbefehl | Bitbreiten | feste Register | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8051 | div ab |
Dieser Fall der Kaskadierung ist bei Mikrocontrollern selten anzutreffen.
Zunächst benötigen Sie einen Divisionsbefehl mit den oben genannten Bitbreiten. Der 8051-Divisionsbefehl ist also nicht geeignet!
Weiterhin darf der Divisor die verfügbare Bitbreite nicht überschreiten! Ist der (bekannte!) Divisor zu groß, kann eine Primfaktorzerlegung zu einer mehrfach hintereinander ausführbaren Division führen, aber das ist meist nicht sinnvoll.
Merke: Kaskadierung ist für überlange
Divisoren nicht möglich und erfordert
stets die folgende Lösung.
Überlange Dividenden sind kein Problem.
Die Kaskadierung ist auch erforderlich, wenn nur der Quotient zu breit wird. Ggf. ist das High-Byte mit Null anzusetzen.
Beispiel (allgemein gehalten) für 16-bit-Quotient:
Dividend / Divisor = Quotient und Rest |
---|
24 bit / 8 bit = 16 bit Rest 8 bit |
a:b / d
=> p Rest r
(b+r):c / d => q Rest r |
Hierbei sind beliebige Bitbreiten realisierbar. Die übliche Routine dividiert 16 bit / 8 bit = 8 bit Rest 8 bit.
Die binäre Division erfolgt genauso wie die schriftliche Division; durch probeweise Subtraktion des (0-oder 1fachen des) Quotienten und Fortfahren zur nächsten Ziffer von links nach rechts.
Zweierkomplement-Zahlen müssen vorher nichtnegativ gemacht werden; das Vorzeichen des Quotienten ergibt sich aus der XOR-Verknüpfung der höchstwertigen Bits von Dividend und Divisor. Der Rest ist ohnhin nur für vorzeichenlose Zahlen definiert.
Anmerkung: Handgeschriebene Divisionen sind, wie oben angeführt,
bei überlangen Divisoren immer vonnöten; auch auf Pentium u. ä.
sind sie in der Laufzeitbibliothek von C bspw. für __int64-Ergebnisse
enthalten!
Wegen der Verwandtschaft der Division zu Verschlüsselungs- und CRC-Routinen ist
ihre Implementierung sehr ähnlich zu jenen Verfahren!
Beispiel: 12345 / 67 = 184 Rest 17 (3039h / 43h = 0B8h Rest 11h)
Dividend | 3039h | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | ||
Subtraktion testen | 60h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1 | ||||||||
subtrahieren | (0EB9h) | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | |||
Subtraktion testen | 3Ah-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0 | ||||||||
unverändert lassen | (0EB9h) | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | ||||
Subtraktion testen | 75h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1 | ||||||||
subtrahieren | (0659h) | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | |||||
Subtraktion testen | 65h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1 | ||||||||
subtrahieren | (229h) | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | ||||||
Subtraktion testen | 45h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1 | ||||||||
subtrahieren | (011h) | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | |||||||
Subtraktion testen | 04h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0 | ||||||||
unverändert lassen | (011h) | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | ||||||||
Subtraktion testen | 08h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0 | ||||||||
unverändert lassen | (011h) | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | |||||||||
Subtraktion testen | 11h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0 | ||||||||
unverändert lassen, = Rest! | 11h | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | Ergebnis 10111000 = 0B8h |
Man beachte beim Subtraktionstest, dass ein vorher herausgeschobenes Übertragsbit auf jeden Fall eine Subtraktion erzwingt; das ist in diesem Beispiel nie der Fall.
Dividend | 3039h | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
linksschieben | 6072h | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | kein Übertrag! | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Subtraktion testen | 60h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
subtrahieren, Bit setzen | 6073h | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1
linksschieben | 3AE6h | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | kein Übertrag!
| Subtraktion testen | 3Ah-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0
| unverändert lassen | 3AE6h | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0
| linksschieben | 75CCh | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | kein Übertrag!
| Subtraktion testen | 75h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1
| subtrahieren, Bit setzen | 32CDh | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1
| linksschieben | 659Ah | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | kein Übertrag!
| Subtraktion testen | 65h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1
| subtrahieren, Bit setzen | 229Bh | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1
| linksschieben | 4536h | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | kein Übertrag!
| Subtraktion testen | 45h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht! | 1
| subtrahieren, Bit setzen | 0237h | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1
| linksschieben | 046Eh | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | kein Übertrag!
| Subtraktion testen | 04h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0
| unverändert lassen | 046Eh | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0
| linksschieben | 08DCh | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | kein Übertrag!
| Subtraktion testen | 08h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0
| unverändert lassen | 08DCh | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0
| linksschieben | 11B8h | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | kein Übertrag!
| Subtraktion testen | 11h-43h | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | geht nicht! | 0
| unverändert lassen | 11B8h | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0
| Ergebnis im Dividenden!! | 11B8h | 00010001 = 11h = 17 | 10111000 = 0B8h = 184
| |
Daraus ergibt sich, dass der Rest stets im High-Teil des Ergebnisses steht, auch beim eingebauten Divisionsbefehl ist das immer so!
Geplant sind downloadbare Makros für alle Mikrocontroller für alle Divisionen mit 8-bit- und 16-bit-Divisoren.
8051 | PIC | AVR | C166 |
---|---|---|---|
Division.a51 | Division.a16 | n.v. | - |
Zur Anwendung kommt die Division (meist durch 10) im Hornerschema
zur Konvertierung einer (beliebig langen) Zahl in die ASCII-Repräsentation
(entsprechend der C-Funktion itoa() oder innerhalb von
printf()).
Zum Anzeigen von Zahlenwerten auf Displays kommt man daher kaum um die
Division herum!