PDA

View Full Version : toDouble() and rounding problem



sadjoker
27th August 2008, 14:21
Hello, guys. I`ve got a little problem
I`m using QT4.4.0+VC++2008
Database SQLite.
I have 3 double columns in the database:
1 = 100000.55
2 = 10000.55
3 = 1000.55

I`m selecting those values and displaying in QLabel



QSqlQuery query("SELECT * FROM main");
double eur, usd, bgn;
while (query.next()) {
eur= query.value(1).toDouble();
usd = query.value(2).toDouble();
bgn= query.value(3).toDouble();
}


but there goes the rounding problem:

1st value goes 100001
2nd value goes 10000.5
3rd value goes 1000.55

What am i missing and how to make 1st value to be shown as 100000.55
I`ve got alot of calculations and that rounding is a problem. Thanx.

PS. If i make it "eur= query.value(1).toString();" it shows the correct value but i need to do calculations and at some time i`ll call str.toDouble() and i get the round again.

wysota
27th August 2008, 15:19
Rounding shouldn't occur with those values and the double type. Are you sure you are not using float?

Try running this app:

#include <QtCore>
#include "stdio.h"

int main(){
QStringList str;
str << "100001" << "10000.5" << "1000.55";
foreach(const QString &s, str){
printf("%f\n", s.toDouble());
}
return 0;
}
It gives me:

$ ./tst
100001.000000
10000.500000
1000.550000

Actually it works correctly with floats as well...


#include <QtCore>
#include <QtDebug>

int main(){
QStringList str;
str << "100001" << "10000.5" << "1000.55";
foreach(const QString &s, str){
double d = s.toDouble();
float f = s.toDouble();
qDebug() << d << f;
}
return 0;
}
yields:

$ ./tst
100001 100001
10000.5 10000.5
1000.55 1000.55

lyuts
27th August 2008, 15:22
What if you do this conversion to double within the SQL query?

sadjoker
27th August 2008, 15:39
I`m using double everywhere. Lemme try your code and i`ll be back.

Edit:


QStringList str;
str << "100000.55" << "10000.55" << "1000.55";
foreach(const QString &s, str){
printf("%f\n", s.toDouble());
qDebug() << "qDebug: " << s.toDouble();
}

This code gives me the next results:

100000.550000
qDebug: 100001

10000.550000
qDebug: 10000.5

1000.550000
qDebug: 1000.55

Why is that rounding and any idea [in code] how to get the real precise value from the database without the rounding?

Edit2: Or should i have to use sprintf(), atof() or something like that so i can get the precise value into a double? That`s too... complicated.

Edit3: wysota, try to put a bigger number with 2 digits after the floating point like 100000.55 and in the second example u gave me it will round the bigger number. It will make it 100001.. thats 0.45 cents gain per calculation. Not good :) no precise

Edit4:


QByteArray eur;

while (query.next()) {
eur = query.value(1).toByteArray();
}
//eur == 100000.55
char *euC = eu.data();
double euDbl = atof(euC);
qDebug() << euC << euDbl;
//result is: 100000.55 100001

What is wrong here... 5 digits numbers get rounded 1 digit after the point, 6 digits numbers get rounded to an integer. OR nothing is wrong and i`m in the biggest math mistake in my life lol :)

100000.55 goes 100001
10000.55 goes 10000.5
1000.55 goes 1000.55
That rounding happens when converting from database result to number (double)
Is it normal? Or using floats or doubles with currencies is a no no.

sadjoker
27th August 2008, 17:10
One more thing... calling


cout << setprecision(14) << eu << endl;

shows exactly what i want... 100000.55 not 100001. But thats only for displaying.

sadjoker
27th August 2008, 17:43
OK, i found a solution [very ugly solution]:



eu = query.value(1).toDouble();
//eu = 100000.55
cout << setprecision(14) << eu << endl;
//result is 100000.55
//now doing some math
eu += 0.30;
cout << setprecision(14) << eu << endl;
//result is 100000.85
//now converting it to QString and entering back into the database
char result[100];
sprintf( result, "%f", eu);
QString stt = QString(QLatin1String(result));
qDebug() << stt;
//result is "100000.850000"
//GREAT :)

jacek
27th August 2008, 18:22
printf("%f\n", s.toDouble());
qDebug() << "qDebug: " << s.toDouble();
}

This code gives me the next results:

100000.550000
qDebug: 100001
You can clearly see here that the problem is not with toDouble(), but qDebug() as you use toDouble() in both lines.


Why is that rounding and any idea [in code] how to get the real precise value from the database without the rounding?
Seeking precision in floating point values is a mistake. If you need precision, esp. if you are counting big amounts of money, better look for arbitrary precision math library like libapmath or gmplib.



OK, i found a solution [very ugly solution]:



eu = query.value(1).toDouble();
//eu = 100000.55
cout << setprecision(14) << eu << endl;
//result is 100000.55
//now doing some math
eu += 0.30;
cout << setprecision(14) << eu << endl;
//result is 100000.85
//now converting it to QString and entering back into the database
char result[100];
sprintf( result, "%f", eu);
QString stt = QString(QLatin1String(result));
qDebug() << stt;
//result is "100000.850000"
//GREAT :)

Here's a shorter version:
eu = query.value(1).toDouble();
...
QString str = QString::number( eu, 'f', 14 );

sadjoker
27th August 2008, 18:58
Wow, thanx jacek. Eventually i would find that static function of QString :) thank you for pointing it out. This forum is such a great place for finding solutions.
For me Qt :p:p:p wouldn`t be the same without qtcentre.

wysota
27th August 2008, 20:21
For me QT wouldn`t be the same without qtcentre.

But QtCentre has nothing to do with QuickTime... ;)

sadjoker
27th August 2008, 22:44
Another solution is to multiply double values by 100 or 1000 or 10000 (depends of the needed digits after the floating point) before storing them like LONG (int) in the database, and dividing values by 100/1000/10000 after extracting from database and before displaying them.

The first solution was: extracting as double from the database. Doing some math with the values, converting them to string and storing back into the db.

Now i have to decide which way to use :)

Lesiok
28th August 2008, 12:47
I think that the best solution is to use specialized class, something like this http://www.programmersheaven.com/download/6698/0/ZipView.aspx