Bug on adding? [SOLVED]



  • Hi

    I am learning QT and have the well known assigment to "calculate the amount of change out of $xx".

    For some reason when running the program, if always changes $0.18 to $0.17. When I use different numbers, the calculation is correct, but anything with $xx.18 is wrong. Here is part of my code:

    @
    double amnt, paid;
    int change, tmp;
    QString chg="";

    amnt = QInputDialog::getDouble(0, "Register", "Enter amount to pay", 0, 0, DBL_MAX, 2);
    paid = QInputDialog::getDouble(0, "Register", "Enter amount paid", 0, 0, DBL_MAX, 2);
    
    cout << amnt << ", " << paid << endl;
    chg = chg + QString("The amount of return is $%1\n").arg(paid-amnt);
    change = (paid-amnt)*100.0;
    

    @

    If I look at the calculation, (paid-amnt)*100.0, the amount is correct, but when this is assigned to the integer "change", something goes wrong. So I am wondering if this is a bug, or if I'm overlooking something in my n00b status.

    Edit: as addition. If I enter amnt=$19.82 and paid=$20, it always calculates "change" to "17"
    If I use $19.83 or $19.81, the amount for "change" is correct to "17" or "19".
    If I enter amnt as $18.82, same thing happens.

    Using QT 4.8.1 for Desktop - MinGW, to compile.

    [Edit: Please use @ tags to wrap code -- mlong] -> OK


  • Moderators

    You have to be careful when using doubles (or floats) to represent money. Both types are inherently imprecise for that purpose and are susceptible to rounding errors internally.



  • I send some variables and calculations to cout, and there things look good:

    19.82, 20
    paid= 20
    amnt= 19.82
    paid-amnt= 0.18
    (paid-amnt)*100= 18
    change= 17

    (change is the result of change = (paid-amnt)*100.0)



  • If I change double to float, the calculation is correct.

    mlong: out of curiosity, if double or floats are imprecise for money, what would one use then instead?



  • [quote author="taeke" date="1342722390"]If I change double to float, the calculation is correct.[/quote]
    Perhaps it is for this calculation, but it will be off even more for others.

    Note that you also may just have a problem properly displaying your result.

    [quote]mlong: out of curiosity, if double or floats are imprecise for money, what would one use then instead?[/quote]
    You use "fixed-point arithmatic":http://en.wikipedia.org/wiki/Fixed-point_arithmetic for that. Qt does not support that natively, but there are 3rd party libraries that do support it.

    The idea is that you you basically calculate with integers, but instead of dollars or cents, you let that integer represent (for instance) 1/1000th of a cent. That way, you also get errors in your final calculation, but the size of these errors is known and predictable.



  • Thank you Andre. The suggestion to use integers, was already in the assigment, but I thought it was merely just for ease of calculation. I did a quick search after your post, and understand the issues with rounding errors for financial calculations, is the main reason. IBM etc have special libraries for financial calculations. Interesting topic.

    But, still I wonder why, why the double of 18.0000, when cast to an integer, all of a sudden is 17. I do know that if the double would be 17.9999, this could become 17 when cast to an integer.



  • If you think that the result of your calculation was 18.0000, or even if that number can be represented exactly in a floating point number, you did not really understand the problems with floating point math yet[*]. Also, you should understand what casting to a different number type really does. Casting to an int truncates the result. So even if your result is 17.99898298927 or something like that, your cast to int will give your 17, not 18.

    [*] Though, it might be that this number could be represented exactly, not sure. I mean that in general, you cannot assume that any number is represented exactly in a floating point variable.



  • I thought I better run the program through the debugger, and it shows clearly what you are saying :) I used a t, where t=paid-amnt. Interesting exercise.

    @
    double:
    amnt 19.82 double
    paid 20 double
    t 0.17999999999999972 double
    change 17 int
    tmp 0 int

    float:
    amnt 19.8199997 float
    paid 20 float
    t 0.180000305 float
    change 18 int
    tmp 0 int
    @

    Thank you Andre!



  • But please: don't change to float because it works in this case. Understand the difference between float and double, and why there may be differences in the results you get. Then, find another way to fix your issue.


  • Moderators

    In addition to Andre's comments, you may want to have a look to rounding "(e.g. qround)":http://qt-project.org/doc/qt-4.8/qtglobal.html#qRound . Just assigning to integers does clipping and not rounding which is of a particular problem. You ran into this with your "pocket money" example above.
    double (around 16) has more significant digits than a float (around 6). When something like your examples work "better" with float than with double, all alarm bells should ring!!



  • Thank you Koahnig. I solved it by multiplying the amounts straight away by 100, after they are entered, to skip any floating point calculations (which works for this exercise).

    Topic is closed for me.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.