Counting change

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • psychofish25
    New Member
    • Jul 2007
    • 60

    Counting change

    I'm brand new to C++, yet I have experience in many other languages. This script I wrote prompts the user for a change amount, then calculates the amounts of each coin that amount is. For example, 37 cents is 1 quarter, 1 dime, and 2 pennies. I have a while loop but it keeps looping when it shouldn't

    Code:
    #include <iostream>
    using namespace std;
    int main(){
    	double input=0.00;
    	int quarters=0;
    	int pennies=0;
    	int dimes=0;
    	int nickels=0;
    	cout<<"Enter the amount you wish to convert: ";
    	cin>>input;
    	do{
    		if(input>0.25){
    			quarters++;
    			input-=0.25;
    		}	
    		else if(input>0.10){
    			dimes++;
    			input-=0.10;
    		}
    		else if(input>0.05){
    			nickels++;
    			input-=0.05;
    		}
    		else if(input>0.01){
    			pennies++;
    			input-=0.01;
    		}
    	}while(input>0.00);
    	cout<<"\n"<<quarters<<" quarters, "<<dimes<<" dimes, "<<nickels<<" nickels, and "<<pennies<<" pennies.\n";
    }
  • gpraghuram
    Recognized Expert Top Contributor
    • Mar 2007
    • 1275

    #2
    Originally posted by psychofish25
    I'm brand new to C++, yet I have experience in many other languages. This script I wrote prompts the user for a change amount, then calculates the amounts of each coin that amount is. For example, 37 cents is 1 quarter, 1 dime, and 2 pennies. I have a while loop but it keeps looping when it shouldn't

    Code:
    #include <iostream>
    using namespace std;
    int main(){
    	double input=0.00;
    	int quarters=0;
    	int pennies=0;
    	int dimes=0;
    	int nickels=0;
    	cout<<"Enter the amount you wish to convert: ";
    	cin>>input;
    	do{
    		if(input>0.25){
    			quarters++;
    			input-=0.25;
    		}	
    		else if(input>0.10){
    			dimes++;
    			input-=0.10;
    		}
    		else if(input>0.05){
    			nickels++;
    			input-=0.05;
    		}
    		else if(input>0.01){
    			pennies++;
    			input-=0.01;
    		}
    	}while(input>0.00);
    	cout<<"\n"<<quarters<<" quarters, "<<dimes<<" dimes, "<<nickels<<" nickels, and "<<pennies<<" pennies.\n";
    }

    It is always advisable not to use double values for checking in loop.
    My idea is convert the double into integer value by multiplying bu 100 and then check it as integer value


    Raghuram

    Comment

    • Simonius
      New Member
      • Feb 2008
      • 47

      #3
      Your problem's a bit obvious if you run a test and watch the value of input.
      If you do you'll notice it stays stuck at 0.01.

      I'll explain it with his example:
      37 this means that input = 37;
      now 25 gets deducted for a quarter so 12 is left.
      now 10 gets deducted for a dime so 2 is left.
      And now a penny gets deducted so input = 0.01.

      There problem is with your test, input = 0.01 but you test for > so you need to replace your > with >= and it'll work.

      And a question about your program, doesn't a quarter = 25 cents?
      Because in your program you deduct 0.25 cents so you'll get about 140ish quarters for 37.

      Comment

      • Banfa
        Recognized Expert Expert
        • Feb 2006
        • 9067

        #4
        Originally posted by Simonius
        And a question about your program, doesn't a quarter = 25 cents?
        Because in your program you deduct 0.25 cents so you'll get about 140ish quarters for 37.
        Not if the input is in dollars :-)

        However the final test against 0.00 in the while loop is a problem. As gpraghuram says using a float or double variable to test for a logical condition is nearly always a bad idea because these variable types only hold an approximation which means that some of the least significant decimal places may not hold the value you are expecting but these places do effect the logical outcome.

        In my opinion it would be better to convert the input from dollars to cents to start with which can be held in an integer value and then do your calculations in cents with the more precise mathematics that integers provide

        [code=cpp]
        double input=0.00;
        int input_as_cents;

        ...

        cout<<"Enter the amount you wish to convert: ";
        cin>>input;

        input_as_cents = static_cast<int >(input*100+0.5 );
        [/code]

        Comment

        • Simonius
          New Member
          • Feb 2008
          • 47

          #5
          True, but his first post says: 37 cents is 1 quarter, 1 dime, and 2 pennies.
          So I assume he's talking about entering an ammount of cents which would eliminate the need for a double.
          And I don't really count bills as change.

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            The fundamental error here is using floating point for money because of that cute little decimal point. Unfortunately, using floating point incurs rounding so all of your comparisons are off. There are actual laws in Europe prohibiting the use of floating point in finance calculations.

            Use integers only and keep the amounts in pennies. That is a quarter is 25. A dollar is 100.

            A integer containing 12345 can be passed to a function that displays it as $123.45.

            Comment

            • psychofish25
              New Member
              • Jul 2007
              • 60

              #7
              Sorry if I wasn't clear in my description. This isn't necessarily a program that I will use when I'm at a restaurant, it's just something simple to try out. I just wanted to take a shot at C++. Anyway, thanks for all your help, my program works now.

              Thanks,
              Jordan

              Comment

              • whodgson
                Contributor
                • Jan 2007
                • 542

                #8
                Assuming you implement the suggestions by 'weaknessforcat s' isn`t it necessary to divide by 25 as well as mod by 25?
                If the input was say (int) 87, 87/25 = 3 to be saved as quarters and 87%25 = 12 which would become the new input for dimes. Now repeat for nickles and thence obtain remainder in cents.
                Also don`t you need to cover the possibility of input being < 25 and > 10?;so that 0 quarters will be recorded.

                Comment

                • Banfa
                  Recognized Expert Expert
                  • Feb 2006
                  • 9067

                  #9
                  Originally posted by whodgson
                  Assuming you implement the suggestions by 'weaknessforcat s' isn`t it necessary to divide by 25 as well as mod by 25?
                  If the input was say (int) 87, 87/25 = 3 to be saved as quarters and 87%25 = 12 which would become the new input for dimes. Now repeat for nickles and thence obtain remainder in cents.
                  Also don`t you need to cover the possibility of input being < 25 and > 10?;so that 0 quarters will be recorded.
                  Actually because of the construction of the program using a while loop all of these cases are handled. Each time round the loop a single coin is accounted for.

                  Using the maths you suggest would make it possible to eliminate the while loop but in it self the program is (or at least does look) functional.

                  Comment

                  • Banfa
                    Recognized Expert Expert
                    • Feb 2006
                    • 9067

                    #10
                    Originally posted by psychofish25
                    Sorry if I wasn't clear in my description. This isn't necessarily a program that I will use when I'm at a restaurant, it's just something simple to try out. I just wanted to take a shot at C++. Anyway, thanks for all your help, my program works now.
                    :D you don't need to apologise all the comments here are made entirely in respect of the code you posted and our suggestions for fixing any errors and improving it and generally suggestion methods of avoiding pitfalls in the future.

                    Most experienced programmers know that floating points and a thing to be used really only for calculation and output of values not control of program logic because the the errors introduced by rounding because floating point types hold approximations to numbers.

                    Look at this example

                    [code=cpp]
                    #include <iostream>
                    #include <iomanip>

                    using namespace std;

                    static const float TEST_VALUE = 1234567800.0F;
                    static const int MAX_LOOP = 100;

                    int main()
                    {
                    float f1 = TEST_VALUE;
                    float f2 = TEST_VALUE;
                    int ix;

                    for(ix=0; ix<MAX_LOOP; ix++)
                    {
                    f2 -= TEST_VALUE/MAX_LOOP;
                    }

                    f1 -= TEST_VALUE;

                    // At this point f1 and f2 should be 0.0
                    // f1 has had the entire value taken away
                    // f2 has had 100 times 1/100 of the value taken away

                    cout << "f1: " << f1 << " : == 0 - " << ((f1==0.0)?"tru e":"false") << endl;
                    cout << "f2: " << f1 << " : == 0 - " << ((f2==0.0)?"tru e":"false") << endl;

                    return 0;
                    }[/code]
                    On my compiler (MS VisualStudio 2005) the output is
                    Code:
                    f1: 0 : == 0 - true
                    f2: 229.92 : == 0 - false
                    Mathematically both values should be 0 (because X - 100 * (X / 100) == X - X == 0) f2 is not equal to 0 because of the rounding errors introduce in doing the calculation in that manor.

                    There actually are ways to compensate for rounding errors when taking small floating point numbers away from large ones for example the Kahan summation algorithm. If I implement this algorithm in my program it becomes

                    [code=cpp]
                    #include <iostream>
                    #include <iomanip>

                    using namespace std;

                    static const float TEST_VALUE = 1234567800.0F;
                    static const int MAX_LOOP = 100;

                    int main()
                    {
                    float f1 = TEST_VALUE;
                    float f2 = TEST_VALUE;
                    float t,y,c;
                    int ix;

                    c = 0.0;
                    for(ix=0; ix<MAX_LOOP; ix++)
                    {
                    y = (-TEST_VALUE/MAX_LOOP) - c;
                    t = f2 + y;
                    c = (t - f2) - y;
                    f2 = t;
                    }

                    f1 -= TEST_VALUE;

                    // At this point f1 and f2 should be 0.0
                    // f1 has had the entire value taken away
                    // f2 has had 100 times 1/100 of the value taken away

                    cout << "f1: " << f1 << " : == 0 - " << ((f1==0.0)?"tru e":"false") << endl;
                    cout << "f2: " << f2 << " : == 0 - " << ((f2==0.0)?"tru e":"false") << endl;

                    return 0;
                    }[/code]

                    and the output is

                    Code:
                    f1: 0 : == 0 - true
                    f2: 8 : == 0 - false
                    f2 has still not reached 0 but it is a lot closer to the correct value. What has happen is that in each iteration of the loop the variable c has been used to carry the loss of precision (rounding error) in taking a large number away from a small number forward to the next iteration so that it may be included there.

                    Comment

                    • weaknessforcats
                      Recognized Expert Expert
                      • Mar 2007
                      • 9214

                      #11
                      At some point I hope you will start using integers for accounting aapplications and avoid all this trouble.

                      I say again, keep your amounts in pennies. In integers.

                      Comment

                      • Banfa
                        Recognized Expert Expert
                        • Feb 2006
                        • 9067

                        #12
                        Originally posted by weaknessforcats
                        I say again, keep your amounts in pennies. In integers.
                        Perhaps I should iterate that I agree on this point, I was just waxing lyrical on the problems of floating point arithmatic and some of the ways of mitigating it in general.

                        In fact you could go a stage further and say that not only for currency but for many situations where you are only interesting in a few decimal places and not extremely large numbers you should consider using integers over floating point numbers.

                        Comment

                        • weaknessforcats
                          Recognized Expert Expert
                          • Mar 2007
                          • 9214

                          #13
                          Yes, indeed. For everything, in fact.

                          As I understand it, floating point came into being to support scientific research where extreme accuracy is often not required. So, unless you are doing some of this research, you should be using integers throughout. Then, if you do use floating point, use only double.

                          Comment

                          Working...