Gleitkommarechnung Fehlerhaft, warum?...
-
ALLE Zahlen werden in ihre binären Entsprechungen umgerechnet.
Befasse dich mit der Umwandlung von Dezimal in Binär und umgekehrt, dann wirst du es verstehen.
0.1 + 07 = ?
Rechne das aus und du wirst verstehen das es auch nicht möglich ist durch Rundung ein exaktes Ergebnis zu bekommen.
Google man nach BCD, das ist auch eine Möglichkeit.
Das sind übrigens Grundkenntnisse für einen Programmierer.
-
-
Cooler Link, danke.
Was mir aber auch mal aufgefallen ist das moderne Compiler bei den meisten Gleitkommaoperationen ein korrektes Ergebnis liefern. Wenn ich es von Hand in Binär umrechne und zurück ist es nicht korrekt, das Programm aber ist wie als wenn ich es nur Dezimal rechne.
Hat das was mit dem Compiler zu tun? Muss es ja eigentlich!
gcc-Version 3.3.4
-
Ich glaube eher die CPU rundet da was rum, kenne mich diesbezüglich aber nicht gut genug aus, als dass ich hier eine qualifizierte Antwort liefern könnte
.
-
Ich werde deinen Quellcode nicht durchlesen und dir die richtige Antwort sagen bevor du nicht lernst deinen Code zu strukturieren!!!!
Außerdem gehört C++ Code in
Solch ein Feld!!!
mfg CSS
-
Ich gebe Dir mit der Strukturierung recht, allerdings sieht mein Quellcode nur hier so aus da ich nicht weiß wie ich es hier anders darstellen soll.
mfg ima_ii
-
Ich glaube, Compiler können wegen Gleitkommarechnung schon was machen. Der aktuelle MSC besitzt zB ein entsprechendes Flag (/fp:)
@CSS
Wie kommst du darauf, dass er seinen Code nicht strukturiert? Und wenn ich mir den Code anschau, dann hat er schon mit C++ Tags gearbeitet, hat nur nicht ganz funktioniert.
-
Hey, die Erläuterung über die Ursache des Fehlers ist mir mittlerweile klar, aber wie bekomme ich mein Problem in den Griff?
Übrigens ein kleiner Fehler ist bei den geld_einheiten, die richtigen Beträge lauten:
double geld_einheiten[anz]={0.1, 0.2, 0.5, 0.10,....
das soll wohl 0.01,0.02,0.05,0.1, ...mfg ima_ii
-
benutz doch festkommazahlen, d.h. integer (z.b. long long), und rechne dann intern in cent, oder bruchteilen davon. das ist beim rechnen mit geldbeträgen ohnehin sinnvoll, da dort häufig ein bestimmte rechengenauigkeit vorgegeben ist.
-
Dein Vorschlag
wird wahrscheinlich funktionieren, ich hoffe aber noch auf eine andere Lösung. Denn was habe ich von Gleitkommadatentypen wenn ich mit denen nicht arbeiten kann weil ich selbst bei einfachen Rechnungen mit Fehler rechnen muß?
-
Das ist so wenn man sich keine Mühe gibt! das muss ich mal so sagen, das ist nicht beleidigend gemeint.
Wenn du mal gegoogelt hättest wüsstest du mehr.Aber zum Compiler: Ich habe mal auf der gcc-Seite geschaut aber ich weiß auch nicht warum der so 'genau' rechnet. Das Problem ist nämlich das ich nicht weiß ob der jetzt dezimal rechnet oder einfach nur rundet. Ich muss weiter suchen, das wundert mich nämlich jetzt.
Cu
-
Ich habe heute min. 3 Stunden gegoogelt,dank eurer Hinweise verstehe ich es jetzt auch warum es zu diesem Fehler kommen muß (Rechnung 0,1+0.7 Binär)
.
Aber was nützt all diese Erkenntnis? Dass ich weiß dass die Datentypen float, double ... nicht verwendbar sind zum Rechnen mit Reellen Zahlen? Dabei hat man mir beigebracht, dass ich diese Datentypen verwenden soll bei Reellen Zahlen und nun?
Ich weiß, dass ich das Problem mittels Festkommazahlen (bzw. Multiplikation mit 100) in den Griff bekomme, aber das kann doch nicht alles sein, oder doch?
Was mache ich, wenn ich einmal ein Programm schreiben möchte, das nach Eingabe beliebiger Gleitpunktzahlen und einer komplizierten Formel ein Ergebnis ausspucken soll? Muss ich dann jede Zahl so umrechnen, dass ich nie mit reellen Zahlen rechne? Das kann ich mir schwer vorstellen, also kann mir damit jemand weiterhelfen?mfg ima_ii
-
Du kannst ganz normal damit rechnen, nur musst du dir halt bewusst sein, dass Rundungsfehler auftreten können. Für double treten sie bei der 15/16. Dezimalstelle auf. Das ist in den meisten Fällen genau genug.
-
Dieser Rundungsfehler bei meinem Bsp. reicht aber aus das dieses Programm so nicht funktioniert. Gibt es denn keinerlei Kontrollmechanismen?
Die muß es geben, denn sonst wäre es zum Bsp nie möglich ein Programm zu schreiben das nach Eingabe von zwei beliebigen Gleitpunktzahlen das Ergebnis einer Division korekt liefert (bleiben wir beim Bsp. 0,7 oder 0,1). Denn bei meinem Programm kann ich dies abfangen (Festkomma), aber nicht bei beliebiger Eingabe eines Users und der simplen Division.
-
Dein Problem ist wohl, dass du falsch rundest (cast nach int schneidet die Nachkommastellen ab). Da wird halt dann aus einem 4.9999999999999998, das eigentlich 5 sein sollte 4.
-
Der cast muß sein, denn ich möchte ja die Ganzahl wissen wie oft die Zahl x in y hineinpaßt --> 5:2=2,5 bzw. 5%2=2R1 --> mit dem Rest rechne ich dann weiter.
mfg
-
ima_ii was würdest du denn dann vorschlagen? das dezimalsystem? dann rechne mal 1/9 ;)(und jetzt sag nicht, das währe keine simple division
). Jedes Zahlensystem ist an irgendeiner stelle nicht genau, und kann es garnicht sein. Wer 100 prozentig genaue zahlen haben will, der wird nicht drumrum kommen, mit "echten" brüchen zu rechnen, anstatt mit dezimalbrüchen, natürlich wird die ausgabe dann nicht so toll funktionieren, aber rundungsfehler kann man dann ausschließen.
-
Dann runde halt auf die 2. Nachkommastelle. Sollte ja bei Geldbeträgen legitim sein.
-
Also, mein Problem mit der Geldausgabe ist gelöst (mittels Runden mit 100).
Meine letzt genannte Frage bezieht sich nicht mehr auf mein Programm, sondern ganz allgemein. Also wie bekomme ich das Problem mit Gleitkommazahlen in den Griff bei einem Programm zur Division? Denn hier weiß ich nicht im voraus wieviele Nachkommastellen der User mir eingibt. Geht dies nur indem ich es z.B. als string einlese und dann auswerte, oder gibt es da noch eine andere Lösung?mfg
PS: Wie bekomme ich Quellcode vernünfig Strukturiert auf dieser Seite dargestellt. Diese Box " C/C++ " kapier ich nicht!
-
ima_ii schrieb:
PS: Wie bekomme ich Quellcode vernünfig Strukturiert auf dieser Seite dargestellt. Diese Box " C/C++ " kapier ich nicht!
Was gibts daran nicht zu kapieren? Du drückst einmal auf C/C++, dann erscheint sowas [ c p p ] (ohne Leerzeichen). Danach fügst du deinen Quellcode ein. Wenn du fertig bist, drückst du wieder auf C/C++ und die Endekennung erscheint [ / c p p ] (wieder ohne Leerzeichen. Wenn du schön artig deinen Spinat gegessen hast und dich stark genug fühlst, kannst du das natürlich auch manuell machen.
Um zu sehen, obs geklappt hat, benutze einfach die Vorschau.