double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;
Ergebnis: 0,2999999999999999889
double a, b;
a = 0.3;
b = 0;
for (char i = 1; i <= 50; i++) {
b = b + a;
};
std::cout.precision(20);
std::cout << b << std::endl;
Ergebnis: 15.000000000000014211
Also .. ‘a’ ist kleiner als es sein sollte. Aber wenn wir ‘a’ 50 Mal nehmen, wird das Ergebnis größer sein, als es sein sollte.
Warum ist das? Und wie erhält man in diesem Fall das richtige Ergebnis?
Geh und lies darüber. Gleitkommaausgaben müssen sorgfältig studiert werden, damit Sie keine gefährlichen Fehler machen.
– Artelios
26. Mai 2010 um 0:26 Uhr
Um genaue Werte zu erhalten, verwenden Sie stattdessen Ganzzahlen (oder einige Bignum-Bibliotheken) const int acc=100; int tmp, a=30/acc, b=0; für (char i=1;i<=50;i++) b=b+a; std::cout << int(b/acc) << "."; tmp=b%acc; if (tmp<10) std::cout << "0"; std::cout << int (tmp); Um die Dinge zu beschleunigen, können Sie eine Potenz von 2 für acc verwenden, damit *,/,% in <<,>>,& umgewandelt wird.
– Spektre
20. August 2013 um 13:07 Uhr
Kubbi
Um die richtigen Ergebnisse zu erhalten, stellen Sie die Genauigkeit nicht größer als für diesen numerischen Typ verfügbar ein:
#include <iostream>
#include <limits>
int main()
{
double a = 0.3;
std::cout.precision(std::numeric_limits<double>::digits10);
std::cout << a << std::endl;
double b = 0;
for (char i = 1; i <= 50; i++) {
b = b + a;
};
std::cout.precision(std::numeric_limits<double>::digits10);
std::cout << b << std::endl;
}
Wenn diese Schleife jedoch 5000 Iterationen statt 50 durchläuft, wird der akkumulierte Fehler auch bei diesem Ansatz angezeigt – so funktionieren Gleitkommazahlen.
+1 für numeric_limits sind definitiv nicht bekannt genug, wie sie sein sollten.
– Kornel Kisielewicz
26. Mai 2010 um 0:47 Uhr
dan04
Warum ist das?
Weil Gleitkommazahlen binär gespeichert werden, wobei 0,3 0,01001100110011001 ist … sich wiederholen, genau wie 1/3 0,333333 ist … sich dezimal wiederholen. Wenn du schreibst 0.3erhalten Sie tatsächlich 0,29999999999999988897769753748434595763683319091796875 (die unendliche binäre Darstellung, gerundet auf 53 signifikante Stellen).
Denken Sie daran, dass es für die Anwendungen, für die Gleitkommazahlen entwickelt wurden, kein Problem darstellt, dass Sie 0,3 nicht exakt darstellen können. Fließkomma wurde entwickelt, um verwendet zu werden mit:
Körperliche Messungen, die oft nur 4 sig Feigen und gemessen werden noch nie bis über 15.
Transzendente Funktionen wie Logarithmen und die trigonometrischen Funktionen, die sowieso nur angenähert werden.
Für die Binär-Dezimal-Umwandlungen im Vergleich zu anderen Fehlerquellen ziemlich irrelevant sind.
Nun, wenn Sie Finanzsoftware schreiben, was 0,30 $ bedeutet exakt 0,30 $, es ist anders. Für diese Situation gibt es dezimale Arithmetikklassen.
Und wie erhält man in diesem Fall das richtige Ergebnis?
Die Begrenzung der Genauigkeit auf 15 signifikante Stellen reicht normalerweise aus, um die “Rausch”-Ziffern zu verbergen. Es sei denn, Sie tatsächlich brauchen eine genaue Antwort, ist dies normalerweise der beste Ansatz.
Vielleicht könnten Sie am Ende Ihres ersten Absatzes ergänzen: “… weil die unendliche Reihe der binären Darstellung von 0,3 irgendwann abgeschnitten wird, weil unendliche Werte nicht auf einem Computer gespeichert werden können”.
– josch
18. August 2016 um 5:46 Uhr
Computer speichern Gleitkommazahlen binär, nicht dezimal.
Viele Zahlen, die dezimal normal aussehen, wie z. B. 0,3, haben keine exakte Darstellung der endlichen Länge im Binärformat.
Daher wählt der Compiler die nächste Zahl aus, die eine exakte binäre Darstellung hat, genau wie Sie schreiben 0.33333 zum 1⁄3.
Wenn Sie viele Fließkommazahlen addieren, summieren sich diese winzigen Unterschiede und Sie erhalten unerwartete Ergebnisse.
Ich denke, die Schlüsselantwort für das OP lautet: “Mit Gleitkommazahlen können Sie nicht das richtige Ergebnis erzielen.” 🙂
– Dash-Tom-Bang
26. Mai 2010 um 1:20 Uhr
Sie erhalten das richtige Ergebnis. Zugegeben, nicht das Ergebnis, das Sie erwartet haben.
– MSalter
26. Mai 2010 um 7:15 Uhr
Es ist nicht so, dass es größer oder kleiner ist, es ist nur physikalisch unmöglich, „0,3“ als exakten Wert in einer binären Gleitkommazahl zu speichern.
Der Weg zum “richtigen” Ergebnis besteht darin, keine 20 Dezimalstellen anzuzeigen.
Um das “richtige” Ergebnis zu erhalten, versuchen Sie es
Geh und lies darüber. Gleitkommaausgaben müssen sorgfältig studiert werden, damit Sie keine gefährlichen Fehler machen.
– Artelios
26. Mai 2010 um 0:26 Uhr
Um genaue Werte zu erhalten, verwenden Sie stattdessen Ganzzahlen (oder einige Bignum-Bibliotheken) const int acc=100; int tmp, a=30/acc, b=0; für (char i=1;i<=50;i++) b=b+a; std::cout << int(b/acc) << "."; tmp=b%acc; if (tmp<10) std::cout << "0"; std::cout << int (tmp); Um die Dinge zu beschleunigen, können Sie eine Potenz von 2 für acc verwenden, damit *,/,% in <<,>>,& umgewandelt wird.
– Spektre
20. August 2013 um 13:07 Uhr