Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Runden zufällig?

7 views
Skip to first unread message

Markus Donath

unread,
Sep 25, 2019, 9:00:04 AM9/25/19
to
Ich habe festgestellt, dass das Runden bei der Ausgabe von
Gleitkommazahlen zufällig zu sein scheint:

double x = 31371.185;
std::cout << std::fixed
<< std::setprecision(3) << x << " ~ "
<< std::setprecision(2) << x
<< std::endl;

double y = 36371.185;
std::cout << std::fixed
<< std::setprecision(3) << y << " ~ "
<< std::setprecision(2) << y
<< std::endl;

Ausgabe:

31371.185 ~ 31371.19
36371.185 ~ 36371.18

Ich habe das mit mehreren C++-Compilern probiert, das Ergebnis ist immer
das selbe.

Markus

Thomas Dorner

unread,
Sep 25, 2019, 11:20:03 AM9/25/19
to
Hallo Markus!

> Ich habe festgestellt, dass das Runden bei der Ausgabe von
> Gleitkommazahlen zufällig zu sein scheint:

Scheint stimmt. :-)

> double x = 31371.185;
> std::cout << std::fixed
> << std::setprecision(3) << x << " ~ "
> << std::setprecision(2) << x
> << std::endl;
>
> double y = 36371.185;
> std::cout << std::fixed
> << std::setprecision(3) << y << " ~ "
> << std::setprecision(2) << y
> << std::endl;
>
> Ausgabe:
>
> 31371.185 ~ 31371.19
> 36371.185 ~ 36371.18
>
> Ich habe das mit mehreren C++-Compilern probiert, das Ergebnis ist
> immer das selbe.

Das liegt an der internen Repräsentation von Gleitkommazahlen,
vermutlich nach IEEE. Wenn Du Dir Deine Zahlen mal ganz genau
anschaust, siehst Du den Grund:

std::cout << std::setprecision(12) << x << "\n" << y << "\n";

31371.185000000001
36371.184999999998

Also alles ganz normal und korrekt. Siehe
https://de.wikipedia.org/wiki/Gleitkommazahl

Viele Grüße, Thomas

Bonita Montero

unread,
Sep 25, 2019, 11:20:04 AM9/25/19
to
Das hängt wohl nicht vom wirklichen Runden ab, sondern davon,
wie die Standard-Bibliothek binäre Floating-Point-Werte in
dezimale wandelt.

Stefan Reuther

unread,
Sep 25, 2019, 12:30:06 PM9/25/19
to
Am 25.09.2019 um 11:27 schrieb Markus Donath:
> Ausgabe:
>
> 31371.185 ~ 31371.19
> 36371.185 ~ 36371.18
>
> Ich habe das mit mehreren C++-Compilern probiert, das Ergebnis ist immer
> das selbe.

Und jetzt noch mal mit setprecision(20).

Das ergibt bei mir 31371.18500000000130967237 und
36371.18499999999767169356, das eine rundet halt knapp auf, und das
andere knapp ab.


Stefan

Markus Donath

unread,
Sep 26, 2019, 6:30:05 AM9/26/19
to
Hallo Thomas,

Und wie geht man damit um? Wenn man Zahlen mit gerade mal 8-stelliger
Mantisse nicht korrekt abbilden kann?
Soll echt Leute geben, die sich über einen falschen Cent in der Anzeige
aufregen. ;)

Markus

Markus Schaaf

unread,
Sep 26, 2019, 7:10:08 AM9/26/19
to
Am 26.09.19 um 09:25 schrieb Markus Donath:

> Und wie geht man damit um?

Darüber gibt es ganze Bücher. Man muss sich der Darstellungs- und
Rundungsgrenzen bewusst sein und in allen Berechnungen eine
Fehlerabschätzung machen, mit angemessener Rundung des Ergebnisses.

> Soll echt Leute geben, die sich über einen falschen Cent in der Anzeige
> aufregen. ;)

Man zählt Geldbeträge nicht mit Gleitkommazahlen.

MfG

Hergen Lehmann

unread,
Sep 26, 2019, 12:50:04 PM9/26/19
to
Am 26.09.19 um 09:25 schrieb Markus Donath:

> Und wie geht man damit um? Wenn man Zahlen mit gerade mal 8-stelliger
> Mantisse nicht korrekt abbilden kann?
> Soll echt Leute geben, die sich über einen falschen Cent in der Anzeige
> aufregen. ;)

Der Wissenschaftler ist sich bewusst, das seine Messwerte eh eine sehr
begrenzte Genauigkeit haben und rundet auf entsprechend wenige Stellen.
Statt "36371.184999999998m" lässt er z.B. "36.4km" ausgeben und alle
sind glücklich, weil das nicht nur sachlich richtiger ist, sondern sich
auch besser lesen lässt.

Der Softwarentwickler im Finanzwesen macht einen ganz großen Bogen um
Gleitkommazahlen und rechnet grundsätzlich mit Festkomma und
wohldefinierten Rundungsregeln. Für einfache Zwecke kann man dafür
Integers missbrauchen (die z.B. Zentel-Cent repräsentieren), für
komplexere Festkomma-Berechungen gibt es Bibliotheken, und das in der
Finanzwelt immer noch weit verbreitete Cobol hat nicht ohne Grund
Festkomma-Datentypen bereits eingebaut.

Markus Donath

unread,
Sep 26, 2019, 12:50:05 PM9/26/19
to

Thomas Dorner

unread,
Sep 26, 2019, 2:10:04 PM9/26/19
to
Hallo Markus!

> Und wie geht man damit um? Wenn man Zahlen mit gerade mal 8-stelliger
> Mantisse nicht korrekt abbilden kann?
> Soll echt Leute geben, die sich über einen falschen Cent in der
> Anzeige aufregen. ;)

Mit Recht, für Geldbeträge nimmt man keine Fließkommazahlen.
Festkommazahlen mit hinreichender Genauigkeit sind hier das Mittel der
Wahl. Zur Zeit der Euro-Umstellung hat mein Arbeitgeber mit 4
Nachkommastellen nach dem Cent (und natürlich Pfennig, Schilling,
Centime, ...) gerechnet, da das damals sogar eine gesetzliche Vorgabe
war (an die sich allerdings etliche nicht gehalten haben). Unsere
Geldbeträge hatten 63 Bit, die Zwischenwerte bei Umrechnungen 124 Bit.

Viele Grüße, Thomas

Markus Donath

unread,
Sep 27, 2019, 3:20:04 AM9/27/19
to
Von daher ist es eigentlich schade, dass C++ keinen eingebauten
Festkomma-Datentyp hat. Eben wie Cobol.

Markus

Bonita Montero

unread,
Sep 27, 2019, 3:20:05 AM9/27/19
to
Da, da kannste sehen wie intern die Nachkommastellen üblicherweise
ermittelt werden und wie sich das auf die "Rundung" auswirkt:

#include <iostream>
#include <string>
#include <cmath>
#include <utility>

using namespace std;

string fractDigits( double d, unsigned digs )
{
string ret;
ret.reserve( digs );
char digit;
d = fabs( d );
d = d - floor( d );
while( digs-- )
d *= 10.0,
digit = (char)d,
d -= digit,
digit += '0',
ret.append( &digit, 1 );
return move( ret );
}

int main()
{
string fd = move( fractDigits( -3.14159265359, 20 ) );
cout << fd << endl;
}

Markus Schaaf

unread,
Sep 27, 2019, 4:10:04 AM9/27/19
to
Am 26.09.19 um 15:08 schrieb Markus Donath:

>> Man zählt Geldbeträge nicht mit Gleitkommazahlen.

> https://github.com/vpiotr/decimal_for_cpp
> tut es.

"Values are stored internally using 64-bit integer"
Selbst wenn, welchen Wert hätte die Information?

Früher, zur Zeit von 16-Bit-CPUs, gab es manchmal einen
Gleitkomma-Coprozessor. Da hat man die Gleitkommazahlen u.U. als Integer
mißbraucht, immerhin hatten die 8 Bit mehr zur Verfügung. Ist aber eher
ein Schülertrick für die Hausaufgaben gewesen, wenn der
Darstellungsbereich so gerade reichte, sparte man sich das Programmieren
eines "BigInt".

MfG

Markus Koßmann

unread,
Sep 27, 2019, 9:20:04 AM9/27/19
to
Markus Donath wrote:
>
> Von daher ist es eigentlich schade, dass C++ keinen eingebauten
> Festkomma-Datentyp hat.
Braucht man einen festeingebauten Festkomma-Datentyp wirklich ?
In C++ sollte man das Dank Operatorüberladung auch mit einer
Klassenbibliothek komfortabel realisieren können. Wie z.B. auch bei
komplexen Zahlen.
Oder meinst du eher, du hättest gerne eine solche Bibliothek im Standard ?
0 new messages