Vorzeichen und 2er-Komplement
|
Die meisten Programmiersprachen bieten unterschiedliche Variablen der
Typen signed und unsigned, manche
auch für mehrere Speichergrößen (z.B. 8 Bit, 16 Bit, 32 Bit ..).
●
Der Werte-Bereich für unsigned (positive ganze Zahlen)
beträgt
vmin=0; vmax=2b-1
Für b=8 Bit ergibt sich z.B. ein Bereich
vmin=0; vmax=28-1=255
●
Für das Vorzeichen von signed Variablen wird 1 Bit
benötigt. Ihr Werte-Bereich beträgt
vmin=-2b-1; vmax=2b-1-1
Für b=8 Bit ergibt sich z.B. ein Bereich
vmin=-27=-128; vmax=27-1=127
|
●
Als Vorzeichen-Bit wird das höchstwertige Bit (msb) verwendet.
Die Zahlen-Bits werden allerdings nur für positive Zahlen in der normalen
binären Form gespeichert.
Sie können das in der Live-Demo testen - Positive signed-Zahlen
innerhalb des zulässigen Werte-Bereichs werden exakt genauso gespeichert
wie unsigned-Zahlen.
●
Negative Zahlen werden nach einem speziellen Algorithmus (2er-Komplement) in ein
Bitmuster umgewandelt. Das bringt Vorteile beim Rechnen auf Prozessor-Ebene.
Negative signed-Zahlen ergeben ein Bitmuster im gleichen
Bereich wie unsigned-Zahlen der oberen Werte-Hälfte
●
Das gleiche Bitmuster kann daher unterschiedlich
interpretiert werden, je nach der vereinbarten Variablen-Type !
Sie können das in der Live-Demo testen, wenn sie
zwischen signed und unsigned umschalten.
|
Umwandlung Negative Zahl → 2er-Komplement
+ Positive Zahlen (innerhalb des Werte-Bereichs) bleiben unverändert.
+ Das Vorzeichen negativer Zahlen wird umgekehrt.
+ Alle Bits werden umgekehrt
+ 1 wird addiert
Beispiel-Vorgaben (Zahl, Speicher-Breite in Bit)
n=-4; b=8;
BitLevel-Algorithmus (ohne Gewähr ! - Javascript bis b<32 )
k=n;
if(k<0) {
mask=(2^b)-1;
k=((~(-k)) & mask)+1;
}
ergibt
k=252
Numerischer Algorithmus (ohne Gewähr ! - Javascript
bis b<56 )
k=n;
if(k<0) {
mask=(2^b);
k=mask+n;
}
|
Umwandlung 2er-Komplement → Negative Zahl
+ Nur Zahlenwerte der oberen Hälfte des Werte-Bereichs werden umgewandelt.
+ 1 wird subtrahiert
+ Alle Bits werden invertiert
+ Das Vorzeichen wird umgekehrt
Beispiel-Vorgaben (Speicherwert, Bit)
k=252; b=8;
BitLevel-Algorithmus (ohne Gewähr !)
n=k;
mask=(2^b)-1;
halb=mask >> 1;
if(n>halb) {n=-((~(n-1)) & mask);}
ergibt
n=-4
Numerischer Algorithmus (ohne Gewähr !)
n=k;
mask=(2^b);
if(n>mask/2) {
n=k-mask;
}
|
Die Bit-Umkehrung mit dem BitLevel NOT-Operator birgt
eine besondere Falle:
Die binäre Darstellung positiver Zahlen enthält theoretisch unendlich
viele führende 0-Bits. Praktisch ist die Anzahl führender 0-Bits durch
die vereinbarte Speicher-Größe (z.B. 8,16,32 Bit) begrenzt. Moderne
Programmiersprachen ohne ausdrückliche Typ-Vereinbarung entscheiden jedoch
selbst die benötigte Speicher-Größe !
Die Bit-Umkehrung verwandelt jedes 0-Bit in ein 1-Bit. Bei dynamischer
Speichergröße ergibt das eine unbekannte Anzahl
führender 1-Bits und damit eine gefährliche Fehlerquelle !
|
Abhilfe:
Nach jeder verdächtigen Operation (z.B. nach Bit-Inversion) wird die Anzahl
der weiter verarbeiteten Bits justiert.
Im Beispiel oben wird das durch Anwendung des BitLevel AND-Operators
mit der Zahl 255 (für 1 Byte Speicherbreite) bewirkt.
Für andere Speicher-Formate (b Bits) verwenden sie
jeweils die Zahl 2b-1
|