Es geht hierbei um die Absicherung vor Überlaufeffekten. Gerade in der Regelungstechnik lassen sich nicht immer Übersteuerungen vermeiden, dann ist Begrenzung und Sättigung nützlich.
Bei der Sättigungsarithmetik von Zweierkomplementzahlen gibt es folgende Fälle zu unterscheiden:
Hierbei geht es um die Einschränkung eines Wertebereiches einer Zahl,
unabhängig von ihrer Herkunft, also Punkt- und Strichrechnung.
Beispielsweise: if (i>10) i=10;
Begrenzung ist in Hochsprachen sehr einfach formulierbar. Siehe Beispiel.
Eine Begrenzung ist auch zweckmäßig bei Bitbreiten-Verringerung; der Übergang zu „Sättigung“ ist in diesem Fall fließend.
Makro-Sammlung (zum Rauskopieren):
PIC | AVR ATmega | 8051 | |
---|---|---|---|
1 Byte in W | 1-Byte-Operanden | 2-Byte-Operanden | 1 Byte in A |
signed X = Maximum aus X und U (untere Grenze) vzb. if (x<u) x=u;
| |||
Vermeiden! |
|
|
|
signed X = Minimum aus X und O (obere Grenze) vzb. if (x>=o) x=o;
| |||
Vermeiden! |
|
|
|
signed X = Eingrenzung von X zwischen U und O vzb. if (x<u) x=u; if (x>=o) x=o;
| |||
Vermeiden! |
|
|
|
unsigned X = Maximum aus X und U (untere Grenze) vzl. if (x<u) x=u;
| |||
|
|
| |
unsigned X = Minimum aus X und O (obere Grenze) vzl. if (x>=o) x=o;
| |||
|
|
| |
unsigned X = Eingrenzung von X zwischen U und O vzl. if (x<u) x=u; if (x>=o) x=o;
| |||
|
|
| |
signed char X = Begrenzung(signed short X) | |||
Vermeiden! |
|
|
0x90 + 0xA0 = 0x130 0x30 ⇒ 0xFF
, hier im Beispiel vzb. 80 + 80 = 160 -96 => 127
Beispiel-Nr. | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
1. Summand | -15 | 3 | 5 | -5 | -127 | -127 | 127 |
2. Summand | 3 | -3 | 10 | -10 | -1 | -2 | 1 |
Summe (8 bit) | -12 | 0 | 15 | -15 | -128 | 127 | -128 |
Überlauf-Flag V | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
Übertrags-Flag C | 0 | 1 | 0 | 1 | 1 | 1 | 0 |
Negativ-Flag N | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
Korrektur | - | - | - | - | ⇒-127 | ⇒-127 | ⇒127 |
Sättigung ist in Hochsprachen nicht direkt verfügbar! Mancher Leser wird entsprechende MMX- oder SSE2-Befehle kennen.
Makro-Sammlung (zum Rauskopieren):
PIC | AVR ATmega | 8051 | |
---|---|---|---|
1 Byte in W | 1-Byte-Operanden | 2-Byte-Operanden | 1 Byte in A |
Vermeiden! Ausweich auf vzl. += vzb. |
|
|
|
vzb. Sättigung nach Addition oder Subtraktion vzb. Zahlen unter Vermeidung von -128 bzw. -32768 | |||
Vermeiden! Ausweich auf vzl. += vzb. |
|
| nicht implementiert |
vzl. Sättigung nach Addition vzl. Zahlen | |||
|
|
|
|
vzl. Sättigung nach Subtraktion vzl. Zahlen | |||
|
|
|
|
vzl. Sättigung nach Addition vzl. (A) + vzb. (B) | |||
Der High-Teil des zweiten (vzb.) Summanden muss angegeben werden | |||
|
|
|
|
vzb. Sättigung nach Addition vzb. (A) + vzl. (B) | |||
Vermeiden! Auflösbar durch Inversion des MSB vor und nach der Rechnung mit vzl. Sättigung. |
Diese Zahlendarstellung hat folgende Eigenschaften:
Die Tabelle zeigt die Ergebnisse für die beiden (kommutativen) Operanden einer Addition an. Grüne Felder bedeuten, dass die Additionsoperation ausgeführt werden kann und eine Überlaufauswertung (trotzdem) das richtige Ergebnis liefert. Die Addition liefert von sich aus NaN nur beim Aufeinandertreffen von +∞ und –∞.
a b | + | +∞ | NaN | –∞ | – |
---|---|---|---|---|---|
+ | + | +∞ | NaN | –∞ | ± |
+∞ | +∞ | +∞ | NaN | NaN | +∞ |
NaN | NaN | NaN | NaN | NaN | NaN |
–∞ | –∞ | NaN | NaN | –∞ | –∞ |
– | ± | +∞ | NaN | –∞ | – |
Nach der Addition führt ein Überlauf (V-Flag gesetzt) zum Ersetzen durch ±∞, je nach Vorzeichen, entgegengesetzt. Das Ergebnis -32768 wird zu –∞ „angepasst“.
Die Subtraktion ergibt sich durch Addition mit der Negation des zweiten Operanden, fertig.
Bei Multiplikation und Division spielt auch die Null eine Sonderrolle.
a b | 0 | + | +∞ | NaN | –∞ | – |
---|---|---|---|---|---|---|
0 | 0 | 0 | NaN | NaN | NaN | 0 |
+ | 0 | + | +∞ | NaN | –∞ | – |
+∞ | NaN | +∞ | +∞ | NaN | –∞ | –∞ |
NaN | NaN | NaN | NaN | NaN | NaN | NaN |
–∞ | NaN | –∞ | –∞ | NaN | +∞ | +∞ |
– | 0 | – | –∞ | NaN | +∞ | + |
Bei der (nichtkommutativen) Division ist die obere Zeile der Dividend, die linke Spalte der Divisor. Da es — anders als bei IEEE-Gleitkommazahlen — keine positive und negative Null gibt, kann die Division durch Null nur mit NaN „bestraft“ werden.
a b | 0 | + | +∞ | NaN | –∞ | – |
---|---|---|---|---|---|---|
0 | NaN | NaN | NaN | NaN | NaN | NaN |
+ | 0 | + | +∞ | NaN | –∞ | – |
+∞ | 0 | 0 | NaN | NaN | NaN | 0 |
NaN | NaN | NaN | NaN | NaN | NaN | NaN |
–∞ | 0 | 0 | NaN | NaN | NaN | 0 |
– | 0 | – | –∞ | NaN | +∞ | + |
Optimal wäre eine Verarbeitung in Silizium. Das ist derzeit nur bei FPGAs möglich. Die Vor- und Nachbetrachtung der Operanden lässt sich hervorragend parallelisieren und benötigt nur wenig zusätzliche Chipfläche.
Um sich nicht in diese vielen Fallunterscheidungen zu verzetteln und Byte-Operanden zur Bewertung heranzuziehen, werden kurzerhand nur die letzten drei Bits einer jeden Zahl betrachtet, nach folgender Vorverarbeitung:
char al=a&7; // Low-Bits kopieren (∞ und NaN abfangend) if (a) { // wenn nicht Null if ((unsigned)a<0x7FFFu) al= 2 ; // positivelse if ((unsigned)a>0x8001u) al= 1 ; // negativ; auch 6 siehe untenelse al^= 4 ; // Bit kippen}
(Das ist nicht dasselbe wie Begrenzung = Bitbreitenreduktion!)
Damit hat al
folgende praktischen Werte:
al | Bedeutung | Bemerkung | |
---|---|---|---|
000 | 0 | Null | |
001 | 1 | negativ | günstig bei Tabellenzugriff |
010 | 2 | positiv | |
011 | 3 | +∞ | |
100 | 4 | NaN | |
101 | 5 | –∞ | |
110 | 6 | negativ | Alternative für programmatische Auswertung |
Die Werte 0, 3, 4 und 5 kommen ohne Berechnungen zu Stande. Damit kann man einen Tabellenzugriff realisieren oder die Auswertung vereinfachen.