Seite 1 von 1
Unerwünschtes Runden
Verfasst: 9. November 2010 22:49
von AlexDu
Guten Abend,
nach ein paar Stunden Fehlersuche hab ich jetzt etwas gefunden, dass ich mir nicht erklären kann.
Code: Alles auswählen
double d = 12345.67;
qDebug() << "test1" << d;
qDebug() << "test2" << QString::number(d,'f',2);
ergibt folgende Ausgabe:
Das Problem tritt nicht nur bei qDebug auf, sondern die Zahlen werden auch so weitergegeben (z.B. in die Datenbank).
Bis zu 4 Stellen vor dem Komma klappt das einwandfrei.
Alex
Verfasst: 10. November 2010 06:33
von Christian81
Und wo ist da jetzt das Problem? Du gibst einer Funktion einen float-Wert ohne eine Angabe wie er ihn zu behandeln hat - was erwartest Du?
Und DB - was für einen Datentyp hat die Spalte, welcher DB-Treiber, ...
Verfasst: 10. November 2010 13:00
von kater
Wiso behandeln? In ein Double passen 15 Stellen oder so und er hat grad mal 7. Was für Informationen sollte man den Computer denn noch geben.
double d = 12345.67;
qDebug() << "test1" << d;
std::cerr << "test2 " << d << "\n";
fprintf(stderr, "test3 %f\n", d);
Ausgabe:
test1 12345.7
test2 12345.7
test3 12345.670000
PS. warum gibt der QtCreator unten bei Application Output nur den Error Stream aus? Dann seh ich ja nie meine Normalen Programmausgaben
grrr Qt suckt, C++ suckt, C <3 Darum liebe ich es. Weil C das tut was man erwartet. Die verd***te Zahl so ausgeben wie ich sie eingegeben habe ^^
Verfasst: 10. November 2010 13:48
von franzf
Bevor man sich so arg in Herzinfarkgefahr begibt, sollte man sich kluglesen:
http://www.cplusplus.com/reference/iost ... ors/fixed/
Vor alle dieser Zusatz:
Notice that the treatment of the precision field differs between the default floating-point notation and the fixed and scientific notations. On the default floating-point notation, the precision field specifies the maximum number of meaningful digits to display both before and after the decimal point, while in both the fixed and scientific notations, the precision filed specifies exactly how many digits to display after the decimal point, even if they are trailing decimal zeros.
std::cout.precision() ist bei mir 6. Im Default-Betrieb also 6 == vor- + nachkommastellen.
Entweder precision anpassen oder auf fixed umstellen, dann ist precision auf die Nachkommastellen angewandt.
Ein Beispiel:
Code: Alles auswählen
#include <iostream>
#include <iomanip>
int main() {
double num = 12345.67;
std::cout << std::cout.precision() << std::endl;
std::ios_base::fmtflags default_flags = std::cout.flags(); // flags speichern
std::cout << std::fixed << num << std::endl;
std::cout.flags(default_flags); // flags resetten
std::cout << num << std::endl;
}
Verfasst: 10. November 2010 14:23
von solarix
Das mit dem Creator kann ich nicht beantworten (im vi sehe ich immer beide Ausgaben

), aber:
kater hat geschrieben:Wiso behandeln? In ein Double passen 15 Stellen oder so und er hat grad mal 7. Was für Informationen sollte man den Computer denn noch geben.
Das ist nicht so einfach... "sehen" tust du die Zahl als Entwickler halt immer als String, welcher (nach bestimmten Regeln) erstellt werden muss. Diese Regeln müssen halt als Entwickler vorgegeben werden (dein '%f'), denn vielfach (eigentlich sogar meistens) möchte man den tatsächlichen Inhalt gar nicht sehen... (Wen interessierts, dass die 6. Nachkommastelle von "double x = 10000000000.0-0.3;" nicht korrekt ist?).
Die gleichen Regeln ergeben die gleichen Ausgaben:
Code: Alles auswählen
fprintf(stderr, "%f %.2f %.1f\n",d,d,d);
qDebug() << QString::number(d,'f') << QString::number(d,'f',2)
<< QString::number(d,'f',1) ;
Also: der Operator "<<" von qDebug für double ist etwas grosszügiger (das 'g'-Format, für verbesserte Lesbarkeit). So what?
Das Problem tritt nicht nur bei qDebug auf, sondern die Zahlen werden auch so weitergegeben (z.B. in die Datenbank).
Wer wandelt denn den double in den (SQL-)String? Also mit bindValue(..) des MySQL-Treibers klappts IMHO schon.. und bei einem direkten exec sollte halt der String auch wieder schön mit korrekten Formaten erstellt werden:
Code: Alles auswählen
qDebug() << "test5" << QString("INSERT INTO ...%1").arg(d,0,'f');
kater hat geschrieben:
Weil C das tut was man erwartet.
LOL <Kommentar wieder gelöscht... weil OT>
[EDIT]
bindValue sollte ziemlich sicher klappen, weil in einem Test QVariant(d).toString() den korrekten Wert ("---.67") ergeben hat...
Verfasst: 10. November 2010 15:15
von kater
franzf hat geschrieben:Bevor man sich so arg in Herzinfarkgefahr begibt, sollte man sich kluglesen:
Hehe, ja ich neige zur Übertreibung manchmal.
Aber danke für die Erklärung Leute, jetzt bin ich wieder etwas schlauer.
Verfasst: 10. November 2010 19:44
von AlexDu
Hallo,
danke für die zahlreichen Erläuterungen.
Ich hatte mich darauf verlassen, dass immer alle Stellen, die ein double fassen kann, in den Umwandlungen mitgeführt werden. Ich hatte auch alles brav gerundet. Da gestern das erstemal fünf Stellen vor dem Komma benutzt wurden hatte ich diverse Fehler in Berechnungen und erstmal Panik. Und wenns um Geld geht hört ja bekanntlich der Spass auf

.
Ich hab jetzt in alle Datenbankupdates QString::number(meinWert) in QString::number(meinWert,'f',2) geändert und alles ist wieder fein.
Gruß Alex
Verfasst: 10. November 2010 19:48
von franzf
AlexDu hat geschrieben:Und wenns um Geld geht hört ja bekanntlich der Spass auf

.
Und wenns ums Geld geht nimmt man sowieso niemals nicht double! Die binäre Darstellung sorgt nur für Probleme, da sie nicht wirklich genau ist.
Nimm unsigned int/long und drücke die Beträge in Cent aus.
Verfasst: 10. November 2010 19:55
von AlexDu
Nimm unsigned int/long und drücke die Beträge in Cent aus.
Keine schlechte Idee. Wenn das Projekt mal fertig ist, wäre das ein weiterer Punkt fürs refactoring.
Gruß Alex
Verfasst: 10. November 2010 21:21
von Christian81
Sorry aber wenn man in einer DB einen String anstatt einen real speichert um Fliesskommawerte abzuspeichern ist man selbst schuld...
Verfasst: 10. November 2010 21:58
von AlexDu
Sorry aber wenn man in einer DB einen String anstatt einen real speichert um Fliesskommawerte abzuspeichern ist man selbst schuld...
Gespeichert werden sie als Numeric (sqlite). Aber wie schon gesagt, am besten gefällt mir die Variante von franzf. Bearbeiten und speichern als Integer (Cent-Beträge), denn im Prinzip ist ja unsere Währung kein Float.
Gruß Alex
Verfasst: 10. November 2010 22:03
von Christian81
[quote="AlexDu"]
Gespeichert werden sie als Numeric (sqlite)/quote]
Und wo ist dann das Problem?