2

just finished my first week of C++(using Visual Studio 2017), I wrote a program that asks the user for the amount of money and will print the number of bills and coins. it works at the beginning, but sometimes it just prints wrong number.(when the user input $1.28, it shows 1 dollar, 1 quarter and 2 pennies.) here is my code, is there anything wrong? the algorithm or the data type?

#include<iostream>
using namespace std;

float Q = 0.25;
float D = 0.10;
float N = 0.05;
float P = 0.01;
float Dollar = 1;
float money;
float dollars, quarters, dimes, nickels, pennies;


int main()  //to break money into coins.
{

cout << "how many money do u have?" << endl;
cin >> money;
dollars = (int)money;
quarters = (int)((money - dollars*Dollar)/Q);
dimes = (int)((money - dollars*Dollar - quarters*Q) / D);
nickels = (int)((money - dollars*Dollar - quarters*Q - dimes*D) / N);
pennies = (int)((money - dollars*Dollar - quarters*Q - dimes*D - nickels*N) / P);
cout << "$" << money << " can be break into :" << endl;
cout << dollars << " dollars. " << endl;
cout << quarters << " quarters. " << endl;
cout << dimes << " dimes. " << endl;
cout << nickels << " nickels. " << endl;
cout << pennies << " pennies. " << endl;
}
Tianyi Liu
  • 21
  • 4
  • Money shouldn't be represented using floating point. Use an int that represents the number of cents for the value. For example, $1.28 would be represented by an int value of 128. You'll need to adjust your math in straightforward ways, but precision won't be a problem. – Michael Burr Oct 05 '17 at 05:33

2 Answers2

0

how to avoid the loss of precision when trying to round number? (C++)

When you convert from floating point to integer, the fractional part is truncated. To ensure no loss of integer precision (getting the right "whole"), add 0.5 to the result each time e.g:

quarters = static_cast<int>(((money - dollars*Dollar)/Q)+0.5);

This however doesn't work when the result is negative e.g: 50.5 - 100 = -49.5 -> +1 = -48.5 -> -48... not 49

For negatives you would want to therefore subtract 0.5.

Werner Erasmus
  • 3,702
  • 14
  • 27
0

I'd assume, that in the line

pennies = (int)((money - dollars*Dollar - quarters*Q - dimes*D - nickels*N) / P);

the part (money - dollars*Dollar - quarters*Q - dimes*D - nickels*N) will produce a value, that is not exactly .03, but a tad below. This is due to the nature of floating point arithmetic, you should read on that. Given that it's something like .029999999995, division by .01 will not yield 3.0, but maybe 2.9999999995. Since you are not rounding, but casting the value to an integer, the whole part after the period will be thrown away, hence it results in 2 pennies.

How can you solve this issue?

The simplest thing will be to round the value instead of casting it, this should yield the correct value, but this is kind of a hacky solution to an issue there is an exact solution for. You could also try to use double instead of a float, but this, too, would not solve the issue. You might get this correct, but the same a similar bug could still occur.

Store whole pennies

You could store the whole amount as an integer (whole pennies)

int amountInPennies;

int penniesPerDollar = 100;
int penniesPerQuarter = 25;
int penniesPerDime = 10;
int penniesPerNickle = 5;

int totalDollars = amountPennies / penniesPerDollar;
int totalQuarters = (amountPennies - totalDollars * penniesPerDollar) / penniesPerQuarter;
...

Decimal types

In a real world application dealing with money (well, depending on the type) you'd most likely go with some kind of decimal type instead of a float. According to this answer there are libraries with arbitrary precisions arithmetic available under the GNU license. You could still roll your own decimal type, that - more or less - does what I presented in the first approach. This might be a great excercise to learn, but maybe a ready-made library would be the better option when it comes to a real world application.

Paul Kertscher
  • 8,484
  • 5
  • 30
  • 51
  • There's no need to store dollars and pennies separately - just represent the value in cents. $1.28 is 128 cents. – Michael Burr Oct 05 '17 at 05:34
  • @MichaelButt True - I'll edit it accordingly. Thanks. – Paul Kertscher Oct 05 '17 at 05:44
  • it is not logical tho, I mean, it just shouldn't give me any data like 0.299999999999, mathematically doesn't make sense – Tianyi Liu Oct 05 '17 at 07:10
  • @TianyiLiu - read about floating point arithmetic. I admit, that the implications are not obvious or *mathematically logical*, but this is what we have. Floating point arithmetics is a tradeoff for generic calculations that comese with its drawbacks. If you have special needs, floating point arithmetic may not be for you. – Paul Kertscher Oct 05 '17 at 07:27