PDA

View Full Version : Floating point imprecision



hardgeus
3rd August 2006, 02:51
OK, I have been programming in C++ for over 10 years now and I've never run into this problem...I've always known that floating point operations are somewhat "fuzzy", but I always assumed it would be down to a resolution that I never encounter...well, in a point of sale app I wrote using QT, I am finding that for purchases totaling over $13,000 I am getting imprecision down to 0.1 (I'm running into 5 cents off)

At first I thought I was crazy, but after doing tons and tons of printfs, it seems that something flaky is going on. I have a function called RoundMoney that does a floor and a couple of divisions to force the float value to two decimal places. What's odd is that when I echo the value with qDebug:

qDebug() << fValue

I get the result I'd expect (I think it's 13125.2) ...but when I use

printf("%.5f\n", fValue);

I am getting the values that are off by a nickel (13125.240 or something close...I don't have my debug output in front of me) Note that my arithmetic comparisons (greater than, less than) reflect the value reported by printf and NOT the qDebug output. If anything, the qDebug output is "wrong" because it doesn't agree with the actual if( x < y ) comparisons I'm making. Basically my code looks roughly like this:

if( fOwed > fPaid ) {
printf("%.3f owed, %.3f paid\n", fOwed, fPaid);
qDebug << fOwed << " owed " << fPaid << " paid";
}

And my output (roughly) is:
13125.240 owed, 13125.200 paid
13125.2 owed, 13125.2 paid

How does QT "know" to truncate that .04??

I am looking for one of two possible solutions:

1) Do whatever the hell it is that QT is doing internally to "know" that I earlier truncated my value and ignore the remaining "imprecise" floating point values

2) Use something besides floating point values and arithmetic. Trolltech seems to have thought of everything with QT, is there some sort of high level "decimal" or "money" class to deal with this?

bood
3rd August 2006, 06:31
IMO, it's just like cout, qDebug has a default precison when print a float, and it happened to be 0.1. But it will not do any harm to your program, it's just an output, so what are u worrying about...?

hardgeus
3rd August 2006, 13:10
IMO, it's just like cout, qDebug has a default precison when print a float, and it happened to be 0.1. But it will not do any harm to your program, it's just an output, so what are u worrying about...?

What I'm worried about is that my software checks to see if the customer is underpaying. You can't have the customer give the cashier a $5 bill to pay a $10 tab. The problem is that once the amount gets large enough, there can be up to a nickel of error. So, yesterday when a customer tried to make a $13125.20 purchase, and paid exactly $13125.20 from their credit card, the software thought that he wasn't paying enough because the variable storing the amount owed was actually $13125.24.

I don't think this is just a problem with qDebug() truncating. I am rounding all of my float values to two significant digits (cents), and I use QString::number() all over my code. Now, it WILL format to just one digit if the final digit is a "0", but it doesn't just automatically truncate to .1 every time. Even qstring::number is seeing the value, which is 13125.24 as 13125.2

I considered the possibility that I am making a mistake (which of course I still may be), but if QString::number() were always truncating to .1 then my users CERTAINLY would have noticed because every total would always be even.

jacek
3rd August 2006, 13:17
Try:
if( fOwed > fPaid ) {
printf("%.3f owed, %.3f paid\n", fOwed, fPaid);
qDebug << fixed << fOwed << " owed " << fPaid << " paid";
}and better don't use floating point numbers for large amounts of money.

jacek
3rd August 2006, 13:42
Even qstring::number is seeing the value, which is 13125.24 as 13125.2

The docs say:
QString QString::number ( double n, char f = 'g', int prec = 6 ) [static]

Here's a small test:

#include <QtDebug>
#include <QString>

int main()
{
qDebug() << QString::number( 13125.24567 );
qDebug() << "f";
qDebug() << QString::number( 13125.24567, 'f', 1 );
qDebug() << QString::number( 13125.24567, 'f', 2 );
qDebug() << QString::number( 13125.24567, 'f', 3 );
qDebug() << "g";
qDebug() << QString::number( 13125.24567, 'g', 6 );
qDebug() << QString::number( 13125.24567, 'g', 7 );
qDebug() << QString::number( 13125.24567, 'g', 8 );
}
Output:

"13125.2"
f
"13125.2"
"13125.25"
"13125.246"
g
"13125.2"
"13125.25"
"13125.246"

As you can see everything depends on what you order QString::number() to do.

hardgeus
3rd August 2006, 15:29
The docs say:

As you can see everything depends on what you order QString::number() to do.

That's the problem...What was happening is I was assigning the values I pulled from the database into my amount textbox using:

txtAmount->setText( QString::number(fValue) );

This was truncating my cents when the value got over 10,000! Then, later, when I pulled it out of the textbox, the value was wrong. I was using the qDebug() to print, and this was masking the error since it was also truncating the cents. This error ONLY occurred when values were over 10,000 (which is unusual in my app) so the problem rarely occurred.

I'm glad this was the problem. I was starting to think that I didn't understand the behavior of floating point numbers!