C++ float Präzision

T_55 schrieb:
7.15631 -> Messwert hat 6 signifikanten Stellen -> float geht ok
0.0715631 -> Messwert hat 8 signifikanten Stellen -> float reicht nicht
Versuch es mal analog zum IEEE754 im Dezimalbereich also so:
(+)1 * 715631 * 10 ^-7
Vorzeichen * Mantisse * 10er Potenz

Die Mantisse hat 6 Stellen und ist damit überhaupt kein Problem. Bei der Umwandlung zu binär kommt es zwar zu den typischen Artefakten, die 6 relevanten Stellen bleiben jedoch unberührt: 0.071563102304935455322265625

Erst wenn die (ganzzahlige) Mantisse länger wird kommt es zwangsweise zur Verfälschung des Wertes.


An der Stelle könnte man dann noch das Fass aufmachen, ob es je nach Wertebereich sinnvoll ist mit Integern zu rechnen :)
 
Zuletzt bearbeitet:
Piktogramm schrieb:
Die Mantisse hat 6 Stellen und ist damit überhaupt kein Problem. Bei der Umwandlung zu binär kommt es zwar zu den typischen Artefakten, die 6 relevanten Stellen bleiben jedoch unberührt: 0.071563102304935455322265625
Klar bei dem Beispiel mögen vielleicht die 8 save sein aber es kann eben bei anderen Zahlen ganz anders sein, man braucht doch daher eine Allgemeinregel die sich am Mindestwert orientiert. Die Range liegt zwischen 6 bis 8. Nochmal aus dem Link von oben:
There are 77 powers of ten, although being at the extremes, 10-38 and 1038 are covered only partially.
When the precision shows a range, like 6-8, it means one segment has 6 digits, another has 7 digits, and another has 8 digits. Actually, it is always in reverse; each power of ten range starts with the higher precision segment and ends with the lower precision segment (as the numbers increase).
A few observations from the table:
  • There are 19 powers of ten with a constant precision (and it’s always 7 digits).
  • There are 18 powers of ten for which precision dips to 6 digits. (Precision as low as 6 digits may surprise you, especially if you have bought into the log10(224 = 16,777,216) ≈ 7.22 argument.)
  • There are three long runs where the precision is 7-8 digits: 10-30 through 10-23, 101 through 108, and 1029 through 1036.
Das heißt um sicher zu gehen muss man von 6 ausgehen weil 6 auch vorkommen kann (selbst wenn es nur einmal wäre).

kuddlmuddl schrieb:
0,1 hätte nach deiner Rechnung nur 1 oder 2 signifikante Stellen - passt aber trotzdem nicht in float oder double.

Das ist akademisch wohl richtig aber für die Praxis doch völlig irrelevant denn mit der Sichtweise dürfte man erst keine floats/doubles benutzen.
Irgendwo fängt doch beim Rechnen immer eine Ungenauigkeit an. Selbst eine Abbildung von doubles als riesige Interger würde nichts genauer machen dort wird einfach gerundet also auch ungenau.

Eine 0.625 ist nun eine 0.625.
Eine 0.1 ist nun eine 0.100000001490116119384765625...
Ist doch für die Praxis egal ob ich eine Zahl mit "echten" 0.1 oder 0.100000001490116119384765625 rechne. Wenn man es genauer will nimmt man double (0.1000000000000000055511151231257827021181583404541015625) und wenn man es noch genauer will irgendwelche anderen libs mit noch mehr Präzision.

Je nach Projekt muss man einfach vorher gucken welche Genauigkeit man benötigt um kein Unsinn zu machen.
Zur sogenannten "Messunsicherheit" gibts auch Leitfäden wie https://www.iso.org/standard/50461.html
 
Hi, ja genau!
Evtl habe ich dich bisher auch nur falsch verstanden.
Mir gings darum, dass du dich nicht drauf verlassen kannst jede Zahl mit 6 Nachkommastellen fehlerfrei abbilden zu können.
Du kannst dich aber darauf verlassen, dass zumindest die ersten 6 Stellen noch korrekt sind und floating Probleme danach erst zuschlagen.

Das Problem kann sehr schnell wachsen, wenn man mit den Werten noch rechnet und sie nicht nur einließt

Zahlen zB nahe Null können viel extremere Fehler verursachen, wenn man durch sie dividiert oder ähnliches
 
T_55 schrieb:
Je nach Projekt muss man einfach vorher gucken welche Genauigkeit man benötigt um kein Unsinn zu machen.
Um auf deine originale Frage zurückzukommen: Das ist die Antwort.

Um das weiter auszuführen: Wenn du die Genauigkeit zwischen double und float vergleichen willst, dann ist die Variante
Code:
if(std::to_string((float)val)==std::to_string(val))
float_good_enough=true;
doch eher Käse.

Daher gibt es für dich zwei mögliche Szenarien:
1.) Du willst die double exakt repräsentiert haben.
=> (double)((float)val)==val
2.) Du willst die double bis zu einer gewissen Präzision repräsentiert haben
2.1) Relativ
=> abs(val)<FLT_MAX&&Epsilon>pow(2,-24)
2.2.) Absolut
=> abs(val)<FLT_MAX&&abs(val-(float)val)<delta

Aber ehrlich: Entweder floats reichen für den Anwendungsfall immer oder gar nicht. Wenn du da hart an der Kante bist, nehm gleich doubles und kauf dir n Riegel RAM.
 
T_55 schrieb:
Klar bei dem Beispiel mögen vielleicht die 8 save sein aber es kann eben bei anderen Zahlen ganz anders sein, man braucht doch daher eine Allgemeinregel die sich am Mindestwert orientiert. Die Range liegt zwischen 6 bis 8. Nochmal aus dem Link von oben
Ich hatte dich falsch verstanden.

Es gibt keine Allgemeinregel. Es muss jedes mal erneut "geschätzt" werden, wie viel Präzision benötigt wird. Gerade bei Modellen zur Simulation hat man ja gern mal +/- 10% Vertrauensintervall beim Ergebnis. Da kann man die Ergebnisse zwar als Double vorhalten und fröhlich als Double rechnen. Sinnvoll ist es aber oft nicht.
Anderseits gibt es auch Simulationen, wo sich auch kleine Fehler fröhlich fortpflanzen, weil man einige tausend mal mit den Werten rechnet und so auch ein Fehler im Bereich 10^-6 der einzelnen Werte bei Zeiten eskaliert.
 
new Account() schrieb:
Ist das nicht sogar ein Beispiel für 6 korrekte Stellen? 4 vor dem Komma und 2 danach.
Die 7te Stelle, dh die dritte nach Komma, dh die 2te Neun erlaubt noch eine Rundung, die das selbe Ergebnis liefert wie der Input es war
 
Code:
1999.10
1999.09
1234.56
Stelle 5 und 6 stimmen nicht überein.

Hier mit noch weniger: https://godbolt.org/z/hfpamZ
Code:
114.100 // Beabsichtigt
114.099 // Eigentlich
123.456 // Stellen
Stellen 4, 5 und 6 sind falsch.

Runden könnte hinhauen.
Ist aber auch nicht trivial, v.a. wenn man die intendierte Genauigkeit nicht kennt. Und du müsstest dann wohl auch auf einen anderen Datentyp ausweichen...
 
Die Nachnull in deinem Beispiel kann man weglassen und die Annahme ist tatsächlich, dass Ausgangswerte auf die selbe Anzahl Stellen gerundet werden wie die Eingabe. Schon allein weil ja bekannt ist, dass die Wandlung zwischen Zahlenräumen Artefakte erzeugt.
 
Zurück
Oben