int, bool, char, floatIEEE 754 definiertfloat) unddouble)Schauen wir uns die Kodierung einmal im Detail an
Vorkomma- und Nachkommaanteil
\(4711.1174_D\)
Nachkommadarstellung mit Exponent
\(0.47111174 \cdot {10}^4_D\)
Die zweite Darstellung wird bei IEEE-754-Gleitkommazahlen verwendet
â Float \(F = (-1)^S \cdot (1 + M) \cdot (2)^E\)
Was bedeutet das jetzt alles? đ€Ż
| Bestandteil | Bits (FP-32) |
|---|---|
| Vorzeichen \(S\) (Sign) | Bit 31 |
| Exponent \(E\) | Bit 30-23 |
| Mantisse \(M\) (Nachkommateil) | Bit 22-0 |
0 â positive Zahl1 â negative ZahlDarstellung mit Bias:
Auf den Exponent wird zusÀtzlich immer eine Konstante addiert
Konstante abhÀngig von der Genauigkeit der Gleitkommazahl
0001 0000
1000 11110000 0000 \(= 0\) â u. a. fĂŒr die Null1111 1111 \(= 255\) â â und Not a Number (=NaN)Verschiebe das Komma bis eine 1 vor dem Komma steht
Das höchstwertige Bit ist Vorkommaanteil
(implizite 1, wird nicht gespeichert)
Restlichen Bits entsprechen dem Nachkommaanteil \(M\)
1000.001
Verschiebung des Kommas, bis nur das MSBit noch vor dem Komma steht
â 1.000001 \(\cdot 2^3\)
Exponent entspricht Anzahl an verschobenen Stellen
â \(E = 3 + B = 3 + 127 = 130\)
Beispiele bis hierher gelten nur fĂŒr einfache Genauigkeit
Berechnungsformel ist allerdings fĂŒr alle gleich
Unterschiede: Wertebereich, Bias und Bitbreite von Exponent und Mantisse
â Ansonsten kein Unterschied in der Berechnung!
| Name | Bits | \(E\) (Bits) | Bias | Min. \(E\) | Max. \(E\) | \(M\) (Bits) |
|---|---|---|---|---|---|---|
| FP-16 (Half) | 16 | 5 | 15 | -14 | 15 | 10 |
| FP-32 (Single) | 32 | 8 | 127 | -126 | 127 | 23 |
| FP-64 (Double) | 64 | 11 | 1023 | -1022 | 1023 | 52 |
0001 0000Nachkommaanteil: Darstellung als Summe von Zweierpotenzen
â \(2^{-1} + 2^{-2} + 2^{-3} + 2^{-4} + ...\)
Beispiel: $0.625_D = 2^{-1} + 2^{-3} = $ .101B
0.011 â \(2^{-2}+ 2^{-3}\)Es gibt verschiedene Online-Tools fĂŒr das Darstellen von IEEE-754-Zahlen, zum Beispiel auf weltz.de
0+0 und -000)0Beispiel: Aus 16.625 = 10000.101B wird:
1. Verschiebe Komma bis hinter die höchste Stelle â 1.0000101 \(\cdot 2^4\)
2. Exponenten $E= 4 + 127 = 131 = $ 10000011
3. Mantisse \(M\) entspricht Nachkommaanteil â 0000101
4. Vorzeichenbit \(S\): Zahl positiv â 0
0100 0001 1000 0101 0000 0000 0000 0000
Berechnung von Gleitkommazahlen braucht auf der CPU viele Schritte
â Verwendung von Gleitkommazahlen ist ein Flaschenhals
Einsatz spezialisierter Hardware-Komponente nur fĂŒr Gleitkommazahlen:
â Floating-Point Unit (FPU)
Auf allen modernen CPUs enthalten
Einige alte CPUs und Mikrocontroller enthalten diese aber nicht
Falls nicht vorhanden, dann RĂŒckfall auf Software-Berechnung
Und wenn wir eine feste Anzahl an Nachkommastellen benötigen?
Lösung: Fixed-Point-Zahlen
Nur per Software möglich, keine ĂŒbliche Hardware-Komponente
Eigene Umsetzung notwendig, C bietet keine vorhandene Implementierung
Beispiel: 16.375D in Fixed-Point-Notation mit 2 Nachkommastellen
10000.011 â 010000.01 (Fixed-Point)
Zeit fĂŒr einen Blick in die CPU
Byte-Order wurde bereits vorgestellt (â )
Es fehlt: Kodierung der Zahlen zur effizienten Verarbeitung
â Jetzt!
0 â positiv1 â negativ1 110 wird doppelt kodiert: \(+0\) â 00 und \(-0\) â 10| Sign | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|
| 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 |
| ⊠| Sign | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|---|
| ⊠| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
â Bei fester Byte-GröĂe Ăberlauf in das nĂ€chste Byte (7 Bits verschwendet)
1 als MSBit0100 1111B1011 000010 wird doppelt kodiert mit +0 (001) und -0 (111)| -128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|
| 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
Keine ĂberprĂŒfung auf das Vorzeichen
â Addition und Subtraktion sind identische Operationen
Keine doppelte Darstellung der 0
Beispiel
\(1\) \(-4\) \(=\) \(-3\) â 1 + (-4) = -3
Umwandlung 1: 00012
Umwandlung (-4)
0100B (+4) â 1011111002Addition: 00012 + 11002 = 11012 â -3
| 0 | 0 | 0 | 1 | |
| + | 1 | 1 | 0 | 0 |
| = | 1 | 1 | 0 | 1 |
Anmerkung: Bitweise Addition erfolgt genau wie bei der schriftlichen Addition
â Ăbertrag (Carry-Over) wird bei der nĂ€chsthöheren Stelle zusĂ€tzlich addiert
Computer verwenden intern das Zweierkomplement
Aufwand fĂŒr Konvertierung < Aufwand fĂŒr Rechenoperationen
Anstatt zwei Operationen
Nur noch eine Operation: Addition
Achtung: Auf der Hardware kommt noch die Byte-Order hinzu!
â Wichtig, wenn Speicher direkt ausgelesen wird
Bereits bekannt: Implizite Umwandlung (automatisch) in einen Datentyp
â Skalar zu booleschem Ausdruck bei if-Blöcken
Alternativ: float zu int bei Zuweisung (und umgekehrt)
float f = 3;
Es fehlt: explizite Umwandlung (manuell) in einen Datentyp, z. B. int zu double
In C gibt es Type Casting
â Bezeichnung fĂŒr explizite Umwandlung
Syntax ist einfach
(T) 3; // Umwandlung in Typ TBeispiel: (int) 3.5;
#include <stdio.h>
int main() {
int i = 13;
double d = (double) i;
printf("%#.02f\n", d);
return 0;
}
đš Achtung: Unerwartete Fehler bei Zwischenschritten durch Umwandlungen
#include <stdio.h>
int main() {
int i = 13, j = 4;
double d = i / j;
printf("%#.02f\n", d);
return 0;
}
Warum geschieht das?
intdouble-Umwandlung erst bei der Zuweisung#include <stdio.h>
int main() {
int i = 13, j = 4;
double d = (double)i / j;
printf("%#.02f\n", d);
return 0;
}
double d = (double) i / j;int = char + int; â int = int + int;char = int + int; â char = (char)(int + int);static_cast
double d = static_cast<double>(3);reinterpret_cast:
int i = reinterpret_cast<int>(3.5f);const_cast)dynamic_cast)Erinnerung an Integer
đš Breite in Bits ist abhĂ€ngig von der Hardwarearchitektur! đš
Unerwartete Effekte bei Type Casting möglich
Besonders bei int auf unterschiedlichen CPU-Architekturen
Dringende Empfehlung: Stattdessen Datentypen mit fester Breite verwenden
â uint8_t, uint16_t, uint32_t, uint64_t
â int8_t, int16_t, int32_t, int64_t
Einbindung ĂŒber den Header <stdint.h>