1

I am making a program called "The Vending Machine" in my C++ class and everything works properly except for one output that's when I use Dollar + Quarter + Quarter, which is supposed to be $1.50 and then the loop should die but it won't. So i was hoping maybe someone here sees something I can't see. The function of this program is to simulate a vending machine where you put in coins (Dollars, quarters, dimes and nickels) until you have enough to buy the candy. When you have enough it is suppose to give you the candy and tell you how much change you get in return.

#include <iostream>
using namespace std;

void countMoney(double change); // þetta fall sér um að telja peninga.
double changeLeft(double money_total); // þetta fall sér um að reikna út afganginn af peningnum

int main()
{

    int a = 0;
    countMoney(a);
    return 0;
}

void countMoney(double change) {

    double dollar=1.00, quarter=0.25, dime=0.10, nickel=0.05;
    double money_total=0.00;
    char answer;

    cout.setf(ios::fixed);
    cout.setf(ios::showpoint);
    cout.precision(2);

    do {
        cout << "A packet of candie costs $1.50. You have inserted $" << money_total << "." << endl;
        cout << "Please insert coins:" << endl;
        cout << "                n - Nickel" << endl
             << "                d - Dime" << endl
             << "                q - Quarter" << endl
             << "                D - Dollar" << endl;
        cin >> answer;

        if(answer == 'D')
            money_total += dollar;
        else if(answer == 'q')
            money_total += quarter;
        else if(answer == 'd')
            money_total += dime;
        else if(answer == 'n')
            money_total += nickel;
        else
            cout << "\'" << answer << "\' is not a valid coin." << endl;

    } while(money_total <= 1.50);

    cout << "Enjoy your candies. Your change is $" << changeLeft(money_total) << ". Please         visit again." << endl;

}

double changeLeft(double money_total) {

    double change;
    change = money_total - 1.50;

    return change;

}
cdhowie
  • 158,093
  • 24
  • 286
  • 300
drleifz
  • 189
  • 3
  • 12
  • 1
    Change the while(money_total <= 1.50) with while(money_total < 1.50) – alkino Sep 15 '14 at 23:11
  • Be careful when comparing doubles. What happends if you add a third quarter, does the loop die? – Javi Sep 15 '14 at 23:11
  • 2
    TL;DR Make the problem smaller. – Dwayne Towell Sep 15 '14 at 23:12
  • man, things are gonna get weird with 0.10 and 0.05 in `double`s – guest Sep 15 '14 at 23:13
  • I got the right output when i while(money_total <= 1.50) to while(money_total < 1.50) Why do you say 0.10 and 0.05 are gonna get weird in double.. Should I use float instead? – drleifz Sep 15 '14 at 23:14
  • 1
    Values such as `0.10` can't be exactly represented in float OR double (think about the principle of representing 1/rd or pi in decimal). – Mark B Sep 15 '14 at 23:16
  • 3
    Neither float nor double, use int only, multiply all by 100. More over it's far less consuming cpu. Read about IEEE 754 to know why float and 0.05 are bad. – alkino Sep 15 '14 at 23:16
  • 2
    Don;t use floating-point types for money. – chris Sep 15 '14 at 23:26

7 Answers7

1

You said, "when I use Dollar + Quarter + Quarter, which is supposed to be $1.50 and then the loop should die but it won't." This sounds to me like you want to change:

while(money_total <= 1.50);

to

while(money_total < 1.50);

so that the loop exits when you hit 1.50.

Dko
  • 820
  • 6
  • 12
1

With all number change to int so you haven't problem of comparison of floating number.

More over I replace the <= with a < because if the change is 0, it's ok too.

#include <iostream>
using namespace std;

void countMoney(); // þetta fall sér um að telja peninga.
int changeLeft(int money_total); // þetta fall sér um að reikna út afganginn af peningnum

int main()
{
    countMoney();
    return 0;
}

void countMoney() {

    int dollar=100, quarter=25, dime=10, nickel=5;
    int money_total=0;
    char answer;

    cout.setf(ios::fixed);
    cout.setf(ios::showpoint);
    cout.precision(2);

    do {
        cout << "A packet of candie costs $1.50. You have inserted $" << ((float)money_total) / 100 << "." << endl;
        cout << "Please insert coins:" << endl;
        cout << "                n - Nickel" << endl
             << "                d - Dime" << endl
             << "                q - Quarter" << endl
             << "                D - Dollar" << endl;
        cin >> answer;

        if(answer == 'D')
            money_total += dollar;
        else if(answer == 'q')
            money_total += quarter;
        else if(answer == 'd')
            money_total += dime;
        else if(answer == 'n')
            money_total += nickel;
        else
            cout << "\'" << answer << "\' is not a valid coin." << endl;

    } while(money_total < 150);

    cout << "Enjoy your candies. Your change is $" << ((float)changeLeft(money_total))/100 << ". Please visit again." << endl;

}

int changeLeft(int money_total) {

    int change;
    change = money_total - 150;

    return change;

}
alkino
  • 760
  • 6
  • 15
1

DO NOT process currency values using floating point values! You risk introducing rounding errors that lead to inaccurate results. Floating point arithmetic is not exact.

If you accept currency values as input, convert them to whole integer cents as soon as possible, by multiplying by (10 * decimal places). So, if you need precision for 2 decimal places, multiple by 100.

If you display currency as output, convert cent values to floating point as late as possible, by dividing by (10 * decimal places). So, if you need precision for 2 decimal places, divide by 100.

Do all of your math using integer arithmetic only. That way, there is no loss of precision, no rounding errors, etc.

For example:

#include <iostream>
using namespace std;

void countMoney();
int changeLeft(int money_total);

int main()
{
    countMoney();
    return 0;
}

void countMoney()
{
    const int dollar = 100, quarter = 25, dime = 10, nickel = 5, penny = 1;
    int money_total = 0;
    char answer;

    cout.setf(ios::fixed);
    cout.setf(ios::showpoint);
    cout.precision(2);

    do
    {
        cout << "A packet of candie costs $1.50. You have inserted $" << (((double)money_total) / 100)  << "." << endl;
        cout << "Please insert coins:" << endl;
        cout << "                p - Penny" << endl
             << "                n - Nickel" << endl
             << "                d - Dime" << endl
             << "                q - Quarter" << endl
             << "                D - Dollar" << endl;
        cin >> answer;

        if (answer == 'D')
            money_total += dollar;
        else if (answer == 'q')
            money_total += quarter;
        else if (answer == 'd')
            money_total += dime;
        else if (answer == 'n')
            money_total += nickel;
        else if (answer == 'p')
            money_total += penny;
        else
            cout << "\'" << answer << "\' is not a valid coin." << endl;
    }
    while (money_total < 150);

    int change = changeLeft(money_total);
    cout << "Enjoy your candies. Your change is $" << (((double)change) / 100) << "." << endl;
    cout << "Please visit again." << endl;
}

int changeLeft(int money_total)
{
    return money_total - 150;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • "If you accept currency values as input, convert them to whole integer cents as soon as possible, by " - not converting them from string to float to int. Instead, fix the string and then convert directly to integer cents. So if the input is `$5` (no .), remove $, append `00` and convert the string `"500"` to cents. If the input is `"1.5"`, append a single `"0"` and remove the dot to produce `"150"`. This is an exact transformation. – MSalters Sep 16 '14 at 09:28
  • @MSalters: Whatever works. The same could be said for converting an int back to a currency string. Convert the int to a string, insert a decimal point in the proper position, and prepend/append the appropriate currency symbol. – Remy Lebeau Sep 16 '14 at 15:57
0

The condition for you while loop is:

money_total <= 1.50

Which means that once you've inserted 1.50, the loop doesn't die yet. It continues until it's more than 1.50. Try changing it to:

money_total < 1.50
0
while(money_total <= 1.50)

That says "keep looping while the total is less than or equal to 1.5." In other words, "only break out of the loop when the total is greater than 1.5". You meant <, not <=.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
0

Checking if two doubles are equal (which you are doing in while(money_total <= 1.50);is dangerous. Therefore, you can do it in different ways:

while (money_total < 1.51) assuming that 0.01 is your minimum increment (or 0.001, etc)

Or

while ((money_total-1.50) < epsilon)where epsilon can be for instance boot::epsilon.

TO know more about this problem: How dangerous is it to compare floating point values? http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

Community
  • 1
  • 1
Javi
  • 3,440
  • 5
  • 29
  • 43
0

You should replace

while (money_total <= 1.50)

with

while (money_total < 1.50 - epsilon)

because with quirks of floating point arithmetics you can get a sum like 1.499999999999.

In your case the choice of epsilon is pretty straightforward: it should be less than the least possible coin, that is 0.01, so this would do fine:

while (money_total < 1.50 - 0.001)
Anton Savin
  • 40,838
  • 8
  • 54
  • 90