Visual C++ rechnet falsch !!!
-
Hallo ich bins mal wieder. Also ich komm gleich auf den Punkt:
float d=20.1; float b=10.2; float c = d+b;Bei c kommt jetzt 30.299999 heraus und nicht 30.3. Das gleiche Problem habe ich auch bei doubles dass er mir die Nachkommastellen verschiebt. An was könnte das denn liegen und wie kann man es beheben ?
Mir round() und so habe ich schon versucht zu runden aber es hilft nichts.
-
Das liegt an der internen Darstellung von Fließkommazahlen. Entweder du rundest, oder du findest dich mit solchen Werten ab. Ist eigentlich auch selten ein wirkliches Problem. Hast du denn einen konkreten Fall, bei dem dich das stört?
-
Ich habe ein Prüfprogramm für ein elek. Gerät und muss exakte Schaltpunkte vergleichen. Daher brauche ich genaue Kommawerte zum Teil auch bis zur 4. Nachkommastelle und so. Liegt das dann an meiner Hardware ( Prozessor etc. ) ?
Und kommt das Problem eig. öfters vor ?
-
schau dir an, wie gleitkommazahlen im rechner festgelegt wurden
http://de.wikipedia.org/wiki/Gleitkommazahl
mantisse, exponent, berechnungsvorschriften..ps: vergleiche von gleitkommazahlen funktionieren nicht.
rechne mit integer?
-
Das ist immer so. Runde einfach. Woher kommt denn diese "round"-Funktion, die du erwähnt hast?
Hier ein Beispiel für eine Rundungsfunktion (hat Martin Richter mal gepostet):
double RoundDouble(double dVal, int iPrec) { // Need a default? ASSERT(iPrec>=0); // Shift double dShift=1.0; for (int i=0; i<iPrec; ++i) dShift *= 10.0; // multiply and split (get integral Part) double dResult, dFrac; if (fabs(dFrac=modf(dVal*dShift,&dResult))>=0.5) // Remove Fraction dResult += dFrac<0.0 ? -1.0:1.0; // Shift it back return dResult/dShift; }
-
Also hab die Funktion gerade mal ausprobiert aber das bringt nichts. Bleibt immer auf 30.299999. Vllt. liegts an "int iPrec". Wie muss ich die Genauigkeit eingeben ? Habe mal ein paar Werte versucht aber geht trotzdem nicht.
-
Wenn du mal auf Ganzzahlen runden willst, kannst du dir eine aufwendige (und zeitintensive) Funktion sparen und das über ein Makro machen, z.B. so:
#define ROUNDTOINT(v) (int)(((v*10.)+5)/10)
-
Ah ok Danke. Aber zu 99 % muss ich halt mit Kommazahlen arbeiten und die Runden Funktion funktioniert bei mir auch nicht. Hat das eig. jeder dann oder kommt das nur ab und zu mal vor ?
-
pmb schrieb:
Ah ok Danke. Aber zu 99 % muss ich halt mit Kommazahlen arbeiten und die Runden Funktion funktioniert bei mir auch nicht. Hat das eig. jeder dann oder kommt das nur ab und zu mal vor ?
Nee, das ist immer so. Na ja, ein gerundeter double-Wert hat ja immer noch das Problem der internen Darstellung. Deine Ausgabe kann dann aber glatt auf z.B. 4 Stellen gerundet sein.
-
Eine Möglichkeit könnte z.B. http://gmplib.org/. Ist zwar in erster Linie zum Rechnen mit großen Zahlen gedacht. Ermöglicht aber wohl auch exaktes rechnen mit Gleitkommazahlen.
-
Und kann man die interne Darstellung irgendwie Richtig anzeigen lassen ? Oder rechnen da 64 Bit Prozessoren genauer ?
-
Multiplizier doch deine int's mit 10000, dann hast du deine vier Stellen Genauigkeit. Btw. dem Mathematiker reicht meist 'mit beliebiger Genauigkeit' und der Fehler den Du machst der liegt irgendwo bei 1*10^-6 und für double ungefähr bei 1*10^-15, bist Du sicher, daß das nicht genug ist?
-
Hallo pmb,
pmb schrieb:
Und kann man die interne Darstellung irgendwie Richtig anzeigen lassen ? Oder rechnen da 64 Bit Prozessoren genauer ?
Du hast das grundlegende Wesen der Fließkommadarstellung nicht richtig verstanden.
Die Fließkommazahl kann nicht so rechnen wie wir Menschen es so erwarten. Lese bitte die Beiträge und den Link auf Wikipedia genau durch.Wenn wir schon bei dem Thema sind, gleich vorneweg ein unerläßlicher Tipp: Unter anderem macht sich der Programmierer "strafbar", Fließkommazahlen auf Gleichheit zu prüfen! z.B.:
float f; f = 0.1; if ( f + 0.2 == 0.3 ) { printf( "gleich!" ); //Du wirst diesen String vermutlich nie sehen. } else { printf( "ungleich!" ); }Nun zu Deinem Problem: In Deinem Fall würde ich Festkomma-Zahlen (nicht Fließkomma!) verwenden.
D.h. eine Integer-Variable (am besten 32bit breit) mit dem Wert 1000 entspricht der Zahl 10,00. Und somit die gleiche Variable mit dem Wert 1 entspricht der gewünschten Zahl 0,01.pmb schrieb:
Oder rechnen da 64 Bit Prozessoren genauer ?
Normalerweise nein!
Fließkommazahlen werden üblicherweise in den Funktionen einer Bibliothek (z.B. math.lib) verarbeitet. Durch Angabe von float, double und long double (compilerabhängig!) legst Du die Genauigkeit und den Wertebereich der Fließkommavariablen von vorneherein fest.
Aber selbst mit einem long double (also 80 Bit Genauigkeit) hast Du den gleichen Effekt, nur statt des Ergebnisses "30.299999" bekommst Du dann halt "30.299999999999999999999" o.ä..Martin
-
pmb schrieb:
Und kann man die interne Darstellung irgendwie Richtig anzeigen lassen ? Oder rechnen da 64 Bit Prozessoren genauer ?
Wie intern gerechnet wird, und wie du das letztlich darstellen willst, sind zwei verschiedene Dinge. Das Rechnen geschieht schon genau genug, keine Sorge, die Darstellung kannst du dann auf x Stellen glatt gerundet machen.
-
Ja ok dann werde ich das mal versuchen. Das komische ist halt das es bei VC 6.0 noch gefunzt hat. Das mit den Fließkommazahlen hab ich schon verstanden. Der Prozessor muss das ja auch in Binärcode umrechnen.......
Aber es hätte ja sein können dass es irgendne Möglichkeit gibt.Danke nochmals für eure Antworten
-
pmb schrieb:
Das komische ist halt das es bei VC 6.0 noch gefunzt hat.
Wie meinst du das??
-
pmb schrieb:
Das komische ist halt das es bei VC 6.0 noch gefunzt hat. Das mit den Fließkommazahlen hab ich schon verstanden.
Das wage ich zu bezweifeln. Aber hier haben ja alle schon die richtigen Tipps gegeben. Ich habe auch ein Programm, welches Werte aus ner Messkarte ausliest. Die haben 6 Nachkommastellen. Verschiebe doch einfach das Komma na hinten und schneide den Rest ab. Da hast du ein paar Probleme weniger. Außerdem is das Vregleichen so auch möglich. Speziell bei deinem Beispiel geht das ja noch. Addiere mal mehrfach 1/3, da hast du noch viel größere Abweichungen.
-
Ich meine dass ich in VC++ 6.0 bei float Zahlen immer das rausbekommen habe was ich wollte also z.B 3.500000000 und nicht 3.4999999999999. Hatte das Problem im 6 er nur mit doubles. Floats funktionierten einwandfrei. Aber ist ja auch egal. Es ist Zeit für Veränderung -----> Visual c++ 2008

-
Quark. An der Floating Point Behandlung hat sich gar nichts geändert.
Dieses Problem gab es schon immer.Siehe auch:
http://www.mpdvc.de/artikel/FloatingPoint.htm
-
Hmm. Hatte es im 6 er aber echt nicht. Zumindest ist es mir beim debugggen nicht aufgefallen
-
pmb schrieb:
Hmm. Hatte es im 6 er aber echt nicht. Zumindest ist es mir beim debugggen nicht aufgefallen
Vielleicht hat der Debugger da schon verschönert dargestellt oder sowas...