Skip to content

Zahlendarstellung im Computer

Zahlendarstellung im Computer


Integer Zahlen

Die Darstellung von ganzzahligen Werten erfolgt im Computer durch das Binärsystem. Jedes Bit enthält eine Ziffer einer Binärzähl.

Bsp: 1210=1101212_{10} = 1101_2


Überlauf

Ende der 1970er Jahre gab es zum Beispiel den Intel C4004 - ein 4 Bit Prozessor. Was passiert wenn man in einem 4Bit-Register den Wert 15 speichert und 1 addiert?

|1111 | 15
+ |0001 | 1
--|-----|-----
1|0000 | 0

Das Ergebnis war 0. Diesen Sprung von der größten darstellbaren Zahl (15) auf die kleinste (0) nennt man Überlauf.


Überlauf (2)

Auch wenn wir heute keine 4Bit-Prozessoren mehr verwenden - das Problem besteht weiterhin.

#include <stdio.h>
int main( void )
{
unsigned char x = 255;
x = x + 1;
printf( "255 + 1 = %d\n", x );
x = 0 - 1;
printf( "0 - 1 = %d\n", x );
return 0;
}
Ausgabe:
255 + 1 = 0
0 - 1 = 255

Der Datentyp legt fest, wie viele Bits für die Speicherung zur Verfügung gestellt werden. Bei unsigned char sind das 8 Bits, also die Zahlen von 0 bis 255.


Signed vs Unsigned

Wir haben auf der vorigen Folie den Datentyp unsigned char kennengelernt. Der Datentyp kann positive Zahlen bis 255 und 0 darstellen.

Für negative Werte benötigt man einen Datentyp der auch das Vorzeichen mit speichert. Im Computer wird dafür ein Bit verwendet, das angibt ob die Zahl positiv oder negativ ist. Für positive Zahlen wird im ersten Bit 0 eingetragen, für negative Werte 1.

Der Datentyp signed char kann die Zahlen von -127 bis +127 aufnehmen.


Signed Beispiel

Die kleinste darstellbare Zahl bei Signed Datentypen so dargestellt, dass das erste Bit 1 ist und alle weiteren Bits 0 sind. Dann wird wieder ganz normal hochgezählt.

4 Bit Beispiel


DezimalBinär
00000
+10001
+20010
+30011
+40100
+50101
+60110
+70111
-81000
-71001
-61010
-51011
-41100
-31101
-21110
-11111

Signed vs Unsigned (2)

Beispiel: Der Wert 1111 1111 entspricht als unsigned char der Dezimalzahl 255. Derselbe Wert entspricht aber als signed char der Dezimalzahl -1.

Es ist also wichtig zu wissen wie eine Zahl im Speicher zu interpretieren ist. Dafür verwenden wir Datentypen.


Überlauf bei Signed Datentypen

Der Überlauf funktioniert bei signed und unsigned auf Bitebene genau gleich. Dem Prozessor ist es also egal ob ihr mit Vorzeichen rechnet oder nicht.

|0111 | 7
+ |0001 | 1
--|-----|-----
|1000 | -8
|1111 | -1
+ |0001 | 1
--|-----|-----
1|0000 | 0

Fließkommazahlen

Eine 32-Bit Fließkommazahl kann Werte zwischen 1037-10^{37} und +1037+10^{37} aufnehmen.

Wie kann das sein? Wenn wir einen ganzzahligen Wert speichern kommen wir doch maximal auf 21010-2*10^{10} bis +21010+2*10^{10}. Dabei können bei einer Kommazahl zwischen zwei ganzen Zahlen doch unendlich viele Zahlen vorkommen.


Interpretation von Fließkommazahlen

Dargestellt werden Fließkommazahlen natürlich wieder mit Bits - ein Computer kennt ja nichts anderes.

Dieses Mal werden die Bits aber in 3 Teile geteilt: Vorzeichen, Exponent und Mantisse.

32 Bit64 Bit
Vorzeichen1 Bit1 Bit
Exponent8 Bit11 Bit
Mantisse23 Bit52 Bit
Summe32 Bit64 Bit

Fließkomma - Vorzeichen

Das Vorzeichen ist schnell erklärt 0 zeigt wie bei den signed Zahlen eine positive Zahl an, 1 eine Negative.


Fließkomma - Mantisse

Die Mantisse kann man wie eine ganzzahlige positive Zahl lesen. Bei 32 Bit haben wir dafür 23 Bit zur Verfügung. Es können also nicht so große Zahlen dargestellt werden, als wenn die ganzen 32 Bit verwendet würden.

Da jede Zahl außer 0 irgendwo mit einer 1 beginnen muss, wird das erste Bit nicht mitgespeichert um Platz zu sparen. Damit können 24 Bit gespeichert werden.


Fließkomma - Exponent

Der Exponent gibt an wo bei der Mantisse das Komma liegt. Er beschreibt also, wie oft der Integerwert verdoppelt oder halbiert werden muss, um den Wert der Fließkommazahl zu erhalten.

Bei einer 8 Bit Mantisse würden die Zahlen von 0 - 255 laufen. Da auch negative Exponenten möglich sind, wird die Zahl 0 auf 127 gelegt. Der Wertebereich verschiebt sich auf -127 bis +127


Fließkomma - Bsp

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
V| Exponent (8) | Mantisse (23)

Die Zahl 1 als Fließkommawert:

Vorzeichen positiv:
0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
V| Exponent (8) | Mantisse (23)
Zahl 1 in der Mantisse - hidden Bit wird nicht gespeichert:
0 ? ? ? ? ? ? ? ? 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
V| Exponent (8) |H| Mantisse (23)
Wir wollen 2^0 = 1 rechnen -> Exponent ist 127, weil 127-127 = 0
0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
V| Exponent (8) |H| Mantisse (23)

Fließkomma - Bsp

Die Zahl 13 als Fließkommawert (binär: 1101):

Vorzeichen positiv:
0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
V| Exponent (8) | Mantisse (23)
Zahl 13 in der Mantisse - hidden Bit wird nicht gespeichert:
0 ? ? ? ? ? ? ? ? 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
V| Exponent (8) |H| Mantisse (23)

Wäre der Exponent 0, so bedeutet dies 1.1011.101, also 120+121+022+1231*2^0 + 1*2^{-1} + 0*2^{-2} + 1*2^{-3}, also Dezimal 1+0.5+0+0.1251+0.5+0+0.125 = 1,625.


Damit 1101 vor dem Komma steht, müssen wir die Bits um drei Stellen verschieben,
also Exponent + 3.

1.62523=1.6258=131.625 * 2^{3} = 1.625 * 8 = 13
oder auch
12(0+3)+12(1+3)+02(2+3)+12(3+3)1*2^{(0+3)} + 1*2^{(-1+3)} + 0*2^{(-2+3)} + 1*2^{(-3+3)}
also
123+122+021+120=8+4+0+1=131*2^{3} + 1*2^{2} + 0*2^{1} + 1*2^{0} = 8+4+0+1 = 13.


Da die Nulldarstellung beim Exponenten 127 ist, müssen wir 127 + 3 = 130 als Binärzahl angeben, das entspricht 10000010.

0 1 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
V| Exponent (8) |H| Mantisse (23)

Addition von Fließkommazahlen


Fließkommazahl Genauigkeit

Zwischen zwei ganzen Zahlen liegen unendlich viele Kommazahlen. Der Computer kann nicht alle Kommazahlen exakt darstellen. Die interpretierte Zahl wird immer errechnet indem die Mantisse mit dem Exponenten potenziert wird.

let nr = 0.2 + 0.4;
console.log(nr);
>> 0.6000000000000001

Fließkommazahlen - Warum?

Wir müssen bei der Arbeit mit Computern oft Tradeoffs eingehen. Legt man einen größeren Wert auf einen Aspekt, kann das negative Auswirkungen auf einen anderen haben. Zum Beispiel gibt es Algorithmen, die schneller das Ergebnis berechnen indem sie mehr Speicher verwenden.

Bei Zahlenwerten müssen wir die Aspekte Präzision (Precision), Wertebereich (Range), und Schnelligkeit (Performance) gegenüberstellen.

Kommazahlen mit fixierter Kommaposition bietet Präzision und gute Geschwindigkeit, es kann aber ein weit geringerer Wertebereich (Range) ausgenutzt werden. Da man in der Computer-Science meist hohe Performanz (Geschwindigkeit) und riesige Wertebereiche (Ranges) braucht, ist die Darstellung mit Gleitkommawerten bevorzugt.


Zahlendatentypen in C#

TypeRangeSize
sbyte-128 bis 127Signed 8-bit integer
byte0 bis 255Unsigned 8-bit integer
short-32.768 bis 32.767Signed 16-bit integer
ushort0 bis 65.535Unsigned 16-bit integer
int-2.147.483.648 bis 2.147.483.647Signed 32-bit integer
uint0 bis 4.294.967.295Unsigned 32-bit integer
long-9.223.372.036.854.775.808 bis 9.223.372.036.854.775.807Signed 64-bit integer
ulong0 bis 18.446.744.073.709.551.615Unsigned 64-bit integer

Zahlendatentypen in C# (2)

TypeApproximate rangePrecisionSize
float±1.51045\pm 1.5 * 10^{-45} bis ±3.41038\pm 3.4 * 10^{38}~ 6-9 digits4 bytes
double±510324\pm 5 * 10^{-324} bis ±1.710308\pm 1.7 * 10^{308}~ 15-17 digits8 bytes
decimal±11028\pm 1 * 10^{-28} bis ±7.92281028\pm 7.9228 * 10^{28}28-29 digits16 bytes

Decimal ist ein Fließkommadatentyp, der jedoch eine viel höhere Präzision als float und double bietet. Er wird z.B. für Berechnungen mit Geldbeträgen verwendet um Ungenauigkeiten zu vermeiden. Berechnungen mit dem decimal Datentype sind jedoch langsamer als mit float oder double.