-2

This is my first time posting here, so if the code is too long, I'll be more than happy to edit it.

I'm making a cashier, a function that makes change.

The odd thing is: If I buy 1.14 for 1.15, I get a penny back. But if I buy .14 for .15 I get no pennies back.

Also, if I buy .15 for .20, I get a nickel back. But if I buy .20 for .25, I get 4 pennies back. I need help understanding why I'm getting four pennies back instead of 0 pennies and 1 nickel like I'm supposed to. I believe something has to be wrong with the division somewhere.

#include <iostream>
#include <cmath>

using namespace std;

int main() {

  double buyAmount = 0.0;
  double paidAmount = 0.0;
  double diffAmount = 0.0;
  double smallChange = 0.0;
  int dollars = 0;
  int quarters = 0;
  int dimes = 0;
  int nickels = 0;
  int pennies = 0;

  cout << "Enter purchase amount: ";
  cin >> buyAmount;
  cout << endl;

  cout << "Enter paid amount: ";
  cin >> paidAmount;
  cout << endl;

  diffAmount = paidAmount - buyAmount;

  if (diffAmount < 0 ) {
     cout << "Error: Make sure paid amount exceeds purchase amount. ";
     cout << endl;
  }

  dollars = floor(diffAmount);
  smallChange = (diffAmount - dollars) * 100  

  quarters = (smallChange / 25);
  smallChange = smallChange - (quarters * 25);
  dimes = (smallChange / 10);
  smallChange = smallChange - (dimes * 10);
  nickels = floor(smallChange / 5);
  smallChange = smallChange - (nickels * 5);
  pennies = floor(smallChange / 1); 

  cout << "Total Change: $" << diffAmount;
  cout << endl << endl;
  cout << "dollars " << dollars << endl;
  cout << "quarters " << quarters << endl;
  cout << "dimes " << dimes << endl;
  cout << "nickels " << nickels << endl;
  cout << "pennies " << pennies << endl;
}
Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
  • 6
    Quick hint: Do not use `double` for money amounts, use an int and store number of pennies. That will make the computation easier (no need to floor, ...). – Nicolas Defranoux Jul 02 '14 at 08:36
  • @Nicolas Dedranoux One of the things I tried to fix it was multiplying smallChange by 100, then removing all of the decimals to whole numbers and removed all of the floats. It still didn't work. But I'll edit it to look like that for future readers. – user139323 Jul 02 '14 at 08:39
  • 1
    Using floating points for currency is strongly discouraged and may be even be forbidden due to issues mentioned by @NicolasDefranoux – Samuel Jul 02 '14 at 08:39
  • @user139323 See also: [Money Pattern](http://martinfowler.com/eaaCatalog/money.html) – πάντα ῥεῖ Jul 02 '14 at 08:40
  • @Samuel, I'll make the changes and see it that works. – user139323 Jul 02 '14 at 08:41
  • 2
    The problem is that floats when you convert 24.9999999999974 to an int, it is 24, not 25. The simplest solution is of course to not use floating point. But if you do want to use it, invest in a function which will round to the nearest integer. – M.M Jul 02 '14 at 08:43
  • I said float earlier but meant floor... – user139323 Jul 02 '14 at 08:51

2 Answers2

0

Floating point arithmetic is not exact. Sometimes you get little errors. e.g. 0.25 / 0.25 can lead to 1 or 0.99999999999999.
If you use floor, that will not work unless you add an extra 'epsilon' to compensate for computation errors, e.g.

quarters = floor(smallChange / 0.25);

could become

const double epsilon = 1E-5;
quarters = floor(smallChange / 0.25 + epsilon);


Ints are still a better idea to manage currency:

int diffAmount = ...; // (pennies or cents).
int dollars = diffAmount / 100;
int smallChange = diffAmount % 100;
int quarters = smallChange / 25;
smallChange -= quarters * 25;
int dimes = smallChange / 10;
smallChange -= dimes * 10;
...

You should also make that data driven: Make a data structure containing the different coins and their values, then write code to loop in that data structure. That will make it easy to switch to another currency (most don't have a quarter coin) or to fix mistakes.

Nicolas Defranoux
  • 2,646
  • 1
  • 10
  • 13
  • How can I assign diffAmount to be an integer if it is the difference between two decimals? I tried it and it doesn't work. – user139323 Jul 02 '14 at 09:06
  • I figured it out. `diffAmount = static_cast((paidAmount - buyAmount) * 100 + 0.5)` – user139323 Jul 02 '14 at 09:15
  • The idea is to manage values as int all the time, enter paidAmount and byAmount as ints (number of pennies). By the way when cashiers types an amount they don't type the decimal point, just always enter values in pennies ;) --- You cast to int works, it's the same effect than a floor. – Nicolas Defranoux Jul 02 '14 at 09:20
0

You shouldn't use floating point as they are not exact.

Instead, read dollars and cents separately into integers and then convert to work entirely in cents.
Integer division will make this work perfectly.
If you just assume that the user will input correctly, you can read like this:

int purchaseDollars = 0;
int purchaseCents = 0;
char decimalPoint;  // Can be anything except a number in this snippet.
std::cin >> purchaseDollars >> decimalPoint >> purchaseCents;
int buyAmount = purchaseCents + 100 * purchaseDollars; // Convert to cents
// Same for paid amount

int diffAmount = paidAmount - buyAmount;
int dollars = diffAmount / 100;   // Integer division makes this work as you want
diffAmount -= dollars;            // Now diffAmount is just the cents
/// and so on...
molbdnilo
  • 64,751
  • 3
  • 43
  • 82