Rundungsverhalten bei float

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
bowie_22
Beiträge: 20
Registriert: Sa Nov 24, 2012 5:52 am

Rundungsverhalten bei float

Beitrag von bowie_22 » Sa Feb 13, 2021 8:04 am

Hi,

ich muss das Verhalten bei einer Zuweisung einer bzgl. der Digits zu langen Fliesskommazahl an eine float-Variable erklären.
Also
Definition+ Initialisierung

Code: Alles auswählen

float x = 908340598.3459387458374;
Wenn ich mir mit dem Debugger anschaue was im Speicher gelandet ist, sieht das so aus.

Code: Alles auswählen

908340608.
Das ist jetzt auf den ersten Blick seltsam, ich hätte 908340598. erwartet.
Es scheint was mit der Anzahl der Digits zu tun zu haben ... in der float.h findet man

Code: Alles auswählen

#define FLT_DECIMAL_DIG  9                       // # of decimal digits of rounding precision
Kann jemand erklären, wie das zustande kommt.
Anmerkung:
Habe es mit VS2019 und gcc getestet, das Verhalten ist mit beiden Compilern gleich.

Wäre klasse, wenn mir da jemand auf die Sprünge helfen könnte.

Gruß

Marcus

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8680
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Rundungsverhalten bei float

Beitrag von Xin » Sa Feb 13, 2021 10:54 am

bowie_22 hat geschrieben:
Sa Feb 13, 2021 8:04 am
ich muss das Verhalten bei einer Zuweisung einer bzgl. der Digits zu langen Fliesskommazahl an eine float-Variable erklären.
Die Frage hat also weniger was mit C++ zu tun, als mit der Frage, wer Deine Hausaufgaben macht? :-)
Alles gut, ist ja eine Verständnisfrage. :-)

Eine der wichtigsten Lektionen beim Umgang mit Rechnern ist, dass Rechner nicht rechnen. Die heißen nur so.
bowie_22 hat geschrieben:
Sa Feb 13, 2021 8:04 am
Also
Definition+ Initialisierung

Code: Alles auswählen

float x = 908340598.3459387458374;
Wenn ich mir mit dem Debugger anschaue was im Speicher gelandet ist, sieht das so aus.

Code: Alles auswählen

908340608.
Das ist jetzt auf den ersten Blick seltsam, ich hätte 908340598. erwartet.
Es scheint was mit der Anzahl der Digits zu tun zu haben ... in der float.h findet man

Code: Alles auswählen

#define FLT_DECIMAL_DIG  9                       // # of decimal digits of rounding precision
Warum FLT_DECIMAL_DIG als 9 definiert ist, kann ich Dir leider nicht erklären.

Aber den Grund, warum die Zahl anders gerundet wird. Das Zauberwort heißt Mantisse. Computer rechnen ja nicht dezimal. Und die Mantisse bei einer 32-Bit-Fließkommazahl hat nur 23 Bit (sic). Auf 23 Bit kann man 7 Dezimalzahlen kodieren, deswegen reichts nicht für irgendwas hinterm Komma. Nun ist Deine Zahl zu groß, das sind ja fast schon 10 Dezimalstellen. Nochmal: Wir kodieren 23 Binärziffern, nicht 9 Dezimalziffern. 2^23 ist 8388608. Nun geht man davon aus, dass die erste Ziffer eine 1 und speichert die schon gar nicht mehr. Damit verzweifacht sich die maximal darstellbare Zahl: 16777216.
Alles was größer ist, passt da jetzt auch nicht mehr rein.
908340608 // <- 9 Stellen
16777216 // <- 8 Stellen

In der Fließkommazahl, die 32 Bit groß ist, gibt es noch 8 Bit für den Exponenten. Die Zahl wird also entsprechend des Exponenten verdoppelt. Damit wir wieder auf eine Bruchzahl kommen, also eine sinnvolle Mantisse wird die 16777216 um 6 Bit verschoben, was einer maximalen Zahl von 1073741824 entspricht, aber die Auflösung der Fließkommazahl ist jetzt auch nicht 0, 1, 2, 3 sondern 0, 64, 128, 192. Auch jeder Zählschritt ist um 6 Bit verschoben. Normalerweise macht man das in die andere Richtung. Ein Exponent von -6 bedeutet, dass die Mantisse in Schritten von 0,015625 gewertet wird. Deswegen haben wir Komma-Zahlen. Dieses Komma fließt durch die Zahl entsprechend des Exponenten - daher "Fließkommazahl".
Bei einer Verschiebung um 6 Bit, also sechs stellen, sind die hintersten 6 Stellen reine Raterei, denn sie passen nicht mehr in die Mantisse.

Das am besten passende Bitmuster bilder also nicht 908340598 ab, sondern 908340608. Das liegt um den Wert 10 daneben. Der Zählschritt darunter wäre aber 54 daneben, da wir ja bei der Zahl in 64er Schritten zählen. Besser kann ein Computer die Zahl nicht auf ein 32 Bit Float abbilden.

Mehr Details? Siehe hier Zahlendarstellung auf dem Computer
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

bowie_22
Beiträge: 20
Registriert: Sa Nov 24, 2012 5:52 am

Re: Rundungsverhalten bei float

Beitrag von bowie_22 » Sa Feb 20, 2021 7:37 am

Hi Xin,

vielen Dank für die ausführliche Anwort.

Antworten