Mathematisch Runden ?
-
Hallo,
ich möchte in meinem Programm etwas ausrechnen lassen und diese Anschließend auf meinem Dialog ausgeben.
Das Rechnen mit zwei Double werten ist kein Problem ! Nur das ausgeben ist jetzt nicht ganz so einfach. Ich muss ja den Double wert in einen CString bekommen und das ganze mache ich momentan so:
Text.Format("%.2lf",Zahl);
Das ist schon mal ganz gut denn so gibt er mir den Wert mit zwei Nachkommastellen an. Mein Problem ist nur wie kann ich das ganze vorher runden ? Da meine Berechnungen öfters mal mehr als zwei Nachkommastellen haben.
Was ich möchte ist das wenn in dem Double der Wert 3,235 steht das er mir den Wert 3,24 Anzeigt. Wenn nun aber 3,234 als Double vorhanden ist soll er mir 3,23 Anzeigen.
Hat zu diesem Problem jemand ne Idee ?
Danke Coolsero
-
Text.Format("%.2lf",Zahl + 0.005);
-
Nicht sehr sauber, aber reicht meistens:
inline double round(double d, int nDecimals) { double dhalf = 0.5; dhalf *= (d < 0 ? (-1) : 1); d = (double)(int)((d * pow(10.0, nDecimals)) + dhalf); d = (double)(d * pow(10.0, (-nDecimals))); return d; }
Grüssli
-
Zahl + 0,005
dann mit 1000 multiplizieren, in int konvertieren(schneidet dir die kommastellen ab)
und dann durch 1000 dividieren und in double konvertieren
-
@Dravere: pow ist sehr ungenau und langsam:
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; }
-
Was spricht gegen Franks Lösung?
-
dEUs schrieb:
Was spricht gegen Franks Lösung?
pow ist langsam und ungenau.
Zudem hätte er es mit einmal pow Aufruf und einer Division einfacher gehabt.
-
Hmm bin ich blind oder wo siehst du da bitte einen pow aufruf?
-
Upps. Sorry. Ich habe mich versehen.
Wenn es nur um die Ausgabe geht, ist dies genügend. Die anderen Lösungen waren zumindest flexibel genug um auf eine beliebige Anzahl von Stellen zu runden.
Nein! Wenn es um eine schnelle Lösung geht, die eine Zahl einfach als Text gerundet ausgibt ist das natürlich am einfachsten.
Ich halte jedoch einen Funktionsaufruf iw RoundFloat(x,2) für sprechender.
-
Abgesehen davon dass die printf() Lösung wohl die optimale ist... würde ich das wohl inetwa so machen:
double RoundDecimal(double v, unsigned decimalPlaces) { double scale = 1.0; double accu = 10.0; unsigned power = 1; while (decimalPlaces > 0) { if (decimalPlaces >= power*2) { power *= 2; accu *= accu; } else { scale *= accu; decimalPlaces -= power; accu = 10.0; power = 1; } } return floor(v * scale + 0.5) / scale; }
-
Frank Erdorf schrieb:
Text.Format("%.2lf",Zahl + 0.005);
Jetzt muss ich mich korrigieren. Diese Lösung ist natürlich falsch!
Weil printf und Format selbst natürlich runden.
Manchmal sollte man sein Gehring einschalten bevor man antwortet!
-
Martin Richter schrieb:
@Dravere: pow ist sehr ungenau und langsam:
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 ich bekomme mit deiner Funktion folgende Werte:
double d=5.1234567890; //echter Wert lt. Debugger: 5.1234567889999996 double e; e=RoundDouble(d,10); //== 5.1234567889999996 e=RoundDouble(d,9); //== 5.1234567889999996 e=RoundDouble(d,8); //== 5.1234567899999996 e=RoundDouble(d,7); //== 5.1234567999999996 e=RoundDouble(d,6); //== 5.1234570000000001 e=RoundDouble(d,5); //== 5.1234599999999997 e=RoundDouble(d,4); //== 5.1234999999999999 e=RoundDouble(d,3); //== 5.1230000000000002 e=RoundDouble(d,2); //== 5.1200000000000001 e=RoundDouble(d,1); //== 5.0999999999999996 e=RoundDouble(d,0); //== 5.0000000000000000 e=round(d,10); //==-0.21474836480000001 e=round(d,9); //==-2.1474836480000001 e=round(d,8); //== 5.1234567900000005 e=round(d,7); //== 5.1234567999999996 e=round(d,6); //== 5.1234570000000001 e=round(d,5); //== 5.1234600000000006 e=round(d,4); //== 5.1234999999999999 e=round(d,3); //== 5.1230000000000002 e=round(d,2); //== 5.1200000000000001 e=round(d,1); //== 5.1000000000000005 e=round(d,0); //== 5.0000000000000000
Ich habe die round() von Dravere mal mit einbezogen, die (zumindest bei einer Stellenanzahl <9) ähnlich präsize ist. Genauer kriegt man es mit C++ nicht hin?
-
Gabs da mal nicht Funktionen wie "floor()" oder "ceil()" ? Waren die nicht zum auf und abrunden da?
-
Uruk-h4j schrieb:
Gabs da mal nicht Funktionen wie "floor()" oder "ceil()" ? Waren die nicht zum auf und abrunden da?
die kann man aber imho nur für das Runden auf Ganzzahlen benutzen.
-
@matze: Das Problem ist nicht C++, sondern FPU-Rechengenauigkeit sowie die interne Darstellung von Gleitkomma-Zahlen. Rationale Zahlen mit einer endlichen Darstellung bzgl. Basis 10 sind periodisch unendlich bzgl. Basis 2.
Damit ist "Runden durch Rechnen" problematisch, ein endgültiges Runden muß bei der Umwandlung in Text erfolgen.
----
@Martin Richter:
So einen Gehring hätt' ich auch gern, gibt es den auch mit akku/solar-betrieb?
----Genauer geht es natürlich mit einer eigenen Langzahl-Arithmetik, siehe Windows' calc.exe