Rundungsproblem durch stof
-
Hallo!
Ich muss in einem Programm einen string in ein float umwandeln. Dabei tritt ein "Rundungsproblem" auf, die Zahl hat eigentlich 6 Nachkommazahlen, die für spätere Berechnungen auch wichtig sind, nach der Conversion hat sie allerdings nur noch 3. Ich habe schon ziemlich viel im Netz gelesen, allerdings das Problem noch nicht lösen können. Könnt ihr mir dabei helfen?Hier mein Code mit dem ich die Conversion teste:
#include <iostream> #include <string> int main() { std::string zahl = "10.661049"; float z; std::size_t* pos =0; z = stof (zahl,pos); std::cout << z << std::endl; }
Damit kriege ich folgendes Warning:
conversion.cpp:8:24: warning: zero as null pointer constant [-Wzero-as-null-pointer-constant] std::size_t* pos = NULL; ^~~~ nullptr /Library/Developer/CommandLineTools/usr/lib/clang/10.0.0/include/stddef.h:100:18: note: expanded from macro 'NULL' # define NULL __null ^
und wenn ich das ignoriere folgende Ausgabe:
10.661
Wo liegt das Problem? Vielen Dank schonmal.
-
In erster Linie ist das ein Anzeigeproblem:
#include <iostream> #include <string> int main() { std::string zahl = "10.661049"; float z; z = stof (zahl); std::cout.precision(8); std::cout << z << std::endl; }
Aber: Wenn es wirklich auf solche Präzision ankommt, dann ist
float
hart am Limit.float
hat so 7-8 Stellen Genauigkeit. Da sollte man vielleicht etwas größeres nehmen.
-
Siehe die Antwort von SeppJ bezüglich deiner Frage. Die Warnung hat mit deinem Problem nichts zu tun. Aber um diese auch noch kurz zu erklären. Wenn du einen Zeiger auf Null setzen möchtest, dann verwende unter C++ das Schlüsselwort
nullptr
. Dieses ist Typsicher und du läufst weniger Gefahr, dass etwas falsches passiert. In deinem Fall kannst du das aber auch ganz weglassen, da das zweite Argument fürstof
optional ist.https://en.cppreference.com/w/cpp/language/nullptr
https://en.cppreference.com/w/cpp/string/basic_string/stof
-
Du musst zwischen interner Darstellung und der Ausgabe unterscheiden.
Sieben signifikante Stellen für einfloat
sind schon an der Grenze.
Und die bleiben auch, unabhängig von der Ausgabe, aber im Bereich der Genauigkeit vonfloat
.Bei der Ausgabe wird gerundet und daher auch nicht alle Stellen ausgegeben
Zudem hast du den Parameter pos nicht begriffen.
Was meinst du, macht das=0
in Zeile 8?
-
Auch ansehenswert: Is floating point math broken?
-
@SeppJ vielen dank, da steckte wirklich der fehler!
-
Noch viel wichtiger, das
KommutativgesetzAssoziativgesetz der Addition bzw. Multiplikation ist bei Gleitkommazahlen nicht gewährleistet. Wenn man große Mengen Zahlen summiert oder multipliziert und z.B. durch Threading die Reihenfolge verändert unterscheiden sich häufig die Ergebnisse!Extrembeispiel
#include <iostream> #include <cstddef> int main () { size_t n = 20000000; float f = 0.0; float step = 1.0/n; // Wichtig! // Mathematisch ist step * n = 1, // demnach muss (step * n) + 1 = 2 sein. // Zuerst wird n mal step aufsummiert, // und anschließend 1 dazu addiert. f = 0.0; for (size_t i = 0; i < n; ++i) { f += step; } f += 1.0; std::cout << f << std::endl; // Hier wird nur die Reihenfolge umgedreht, // wegen der numerischen Auslöschung bekommen // wir ein anderes Ergebnis. f = 1.0; for (size_t i = 0; i < n; ++i) { f += step; } std::cout << f << std::endl; return EXIT_SUCCESS; }
-
Assoziativität (von mehr als zwei Zahlen) gilt ebenfalls nicht. Floating Points haben überhaupt ganz andere Rechengesetze als die rationalen oder gar die reellen Zahlen. Aber halt auch wiederum nicht so anders, als dass sie für ihren vorgesehenen Einsatzzweck (reelle Zahlen im computer zu approximieren) nicht geeignet wären. Man muss aber halt wissen, was man tut, wenn es auf numerische Genauigkeit ankommt.
-
@john-0 sagte in Rundungsproblem durch stof:
Kommutativgesetz der Addition bzw. Multiplikation ist bei Gleitkommazahlen nicht gewährleistet
Kann es sein, dass du Assoziativität mit Kummutativität verwechselst?
Dein Beispiel zeigt nicht, dass das KG verletzt ist, da auch auch noch das AG anwendest. Mindestens eines der Gesetze ist verletzt.
Mit s=step:
a) ist
In b) berechnest du aber , was du durch Änderung der Assiziativität bekommst und dann noch durch Kommutativität.
Wenn du eine Aussage nur über das KG treffen wolltest, müsstest du mit a) vergleichen.Es gilt bei IEEE-754-Floats nämlich in der Tat das Kommutativgesetz, aber nicht das Assoziativgesetz (für * und +).
@SeppJ Assoziativität (von mehr als zwei Zahlen) gilt ebenfalls nicht.
Steiche das "ebenfalls".
-
@wob sagte in Rundungsproblem durch stof:
Kann es sein, dass du Assoziativität mit Kummutativität verwechselst?
Ups, ja ich habe zuviel an Kommutatoren bei Summen gedacht.