Why does this fail?

This is a discussion on Why does this fail? within the C++ Programming forums, part of the General Programming Boards category; I have tried in vain to debug this. The logic seems to fail around dimes. For most of the values ...

  1. #1
    Registered User
    Join Date
    Aug 2005
    Posts
    28

    Why does this fail?

    I have tried in vain to debug this. The logic seems to fail around dimes. For most of the values I put in, the logic works fine. However sometimes, there will be a "penny" left in difference and other times there will be a negative number. Any ideas how this happens?

    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
    // self documenting code begin
    	cout << "This program calculates the amount of change\ngiven back after a purchase";
    // self documening code end
    	cout << "\nEnter the purchase amount:  ";
    	double purchase;
    	cin >> purchase;
    	cout << "\nEnter the amount of money given:  ";
    	double money;
    	cin >> money;
    	double difference = money - purchase;
    	double change = difference;
    	int dollar = 1;
    	double halfDollar = .5;
    	double quarter = .25;
    	double dime = .1;
    	double nickel = .05;
    	double penny = .01;
    	for (int dollars = 0; difference >= 1; dollars++)
    	{
    		cout << difference <<"  DEBUGGING LOGIC - subtracting a dollar\n"; // for debugging
    		difference = difference - dollar;
    		cout << difference <<"  DEBUGGING LOGIC - I subtracted a dollar\n"; // for debugging
    	}
    	for (int halfDollars = 0; difference >= 0.50; halfDollars++)
    	{
    		cout << difference <<"  DEBUGGING LOGIC - subtracting a half dollar\n"; // for debugging
    		difference = difference - halfDollar;
    		cout << difference <<"  DEBUGGING LOGIC - I subtracted a half dollar\n"; // for debugging
    	}
    	for (int quarters = 0; difference >= 0.25; quarters++)
    	{
    		cout << difference <<"  DEBUGGING LOGIC - subtracting a quarter\n"; // for debugging
    		difference = difference - quarter;
    		cout << difference <<"  DEBUGGING LOGIC - I subtracted a quarter\n"; // for debugging
    	}
    	for (int dimes = 0; difference >= 0.10; dimes++)
    	{
    		cout << difference <<"  DEBUGGING LOGIC! - subtracting a dime\n"; // for debugging
    		difference = difference - dime;
    		cout << difference <<"  DEBUGGING LOGIC - I subtracted a dime\n"; // for debugging
    	}
    	for (int nickels = 0; difference >= 0.05; nickels++)
    	{
    		cout << difference <<"  DEBUGGING LOGIC - subtracting a nickel\n"; // for debugging
    		difference = difference - nickel;
    		cout << difference <<"  DEBUGGING LOGIC - I subtracted a nickel\n"; // for debugging
    	}
    	for (int pennies = 0; difference > 0.01; pennies++)
    	{
    		cout << difference <<"  DEBUGGING LOGIC! - subtracting a penny\n"; // for debugging
    		difference = difference - penny;
    		cout << difference <<"  DEBUGGING LOGIC - I subtracted a penny\n"; // for debugging
    	}
    	if (difference > 0.01)
    	{
    		cout << difference <<"  DEBUGGING LOGIC! - Added a penny to make it right?\n"; // for debugging
    		++pennies;
    	}
    	if (difference < 0)
    	{
    		cout << difference <<"  DEBUGGING LOGIC! - Subtracted a penny to make it right?\n"; // for debugging
    		--pennies;
    	}
    
    	 // Self documenting output to screen
    	cout << difference <<"  THE END RESULT OF DIFFERENCE DEBUGGING LOGIC!\n"; // for debugging
    	cout << "\nPlease give the customer "  << change << " back in change\n";
    	cout <<  dollars << " dollars\n";
    	cout <<  halfDollars << " half dollars\n";
    	cout <<  quarters << " quarters\n";
    	cout <<  dimes << " dimes\n";
    	cout <<  nickels << " nickels\n";
    	cout <<  pennies << " pennies\n";
    	cin.ignore();
    	return 0;
    	}

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,434
    Try doing it using an integer counting the number of cents, not a double containing the fractions of a dollar.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    #define WORLD "sad place" LinuxCoder's Avatar
    Join Date
    Mar 2006
    Location
    Portugal
    Posts
    89
    I picke up your code and changed some stuff. Please try:
    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
    double dollar = 1;
    double halfDollar = .5;
    double quarter = .25;
    double dime = .1;
    double nickel = .05;
    double penny = .01;
    
    double purchase;
    double money;
    double change;
    double difference;
    
    do {
            cout << "This program calculates the amount of difference\ngiven back after a purchase";
            cout << "\nEnter the purchase amount:  ";
            cin >> purchase;
            cout << "\nEnter the amount of money given:  ";
            cin >> money;
            change = difference = money - purchase;
    
            if (difference<0) { cout << "You'll loose money if the client pays less than the good's price...\n\n"; }
    
    } while (difference<0);
    
    int dollars = 0;
    for (; difference >= dollar; dollars++)
    {
    cout << difference <<"  DEBUGGING LOGIC - subtracting a dollar\n"; // for debugging
    difference -= dollar;
    cout << difference <<"  DEBUGGING LOGIC - I subtracted a dollar\n"; // for debugging
    }
    
    int halfDollars = 0;
    for (; difference >= halfDollar; halfDollars++)
    {
    cout << difference <<"  DEBUGGING LOGIC - subtracting a half dollar\n"; // for debugging
    difference -= halfDollar;
    cout << difference <<"  DEBUGGING LOGIC - I subtracted a half dollar\n"; // for debugging
    }
    
    int quarters = 0;
    for (; difference >= quarter; quarters++)
    {
    cout << difference <<"  DEBUGGING LOGIC - subtracting a quarter\n"; // for debugging
    difference -= quarter;
    cout << difference <<"  DEBUGGING LOGIC - I subtracted a quarter\n"; // for debugging
    }
    
    int dimes = 0;
    for (; difference >= dime; dimes++)
    {
    cout << difference <<"  DEBUGGING LOGIC! - subtracting a dime\n"; // for debugging
    difference -= dime;
    cout << difference <<"  DEBUGGING LOGIC - I subtracted a dime\n"; // for debugging
    }
    
    int nickels = 0;
    for (; difference >= nickel; nickels++)
    {
    cout << difference <<"  DEBUGGING LOGIC - subtracting a nickel\n"; // for debugging
    difference -= nickel;
    cout << difference <<"  DEBUGGING LOGIC - I subtracted a nickel\n"; // for debugging
    }
    
    int pennies = 0;
    for (; difference > penny; pennies++)
    {
    cout << difference <<"  DEBUGGING LOGIC! - subtracting a penny\n"; // for debugging
    difference -= penny;
    cout << difference <<"  DEBUGGING LOGIC - I subtracted a penny\n"; // for debugging
    }
    
    
    if (difference > penny)
    {
    cout << difference <<"  DEBUGGING LOGIC! - Added a penny to make it right?\n"; // for debugging
    ++pennies;
    }
    
    if (difference < 0)
    {
    cout << difference <<"  DEBUGGING LOGIC! - Subtracted a penny to make it right?\n"; // for debugging
    --pennies;
    }
    
    // Self documenting output to screen
    cout << difference <<"  THE END RESULT OF DIFFERENCE DEBUGGING LOGIC!\n"; // for debugging
    cout << "\nPlease give the customer "  << change << " back in change\n";
    cout <<  dollars << " dollars\n";
    cout <<  halfDollars << " half dollars\n";
    cout <<  quarters << " quarters\n";
    cout <<  dimes << " dimes\n";
    cout <<  nickels << " nickels\n";
    cout <<  pennies << " pennies\n";
    cin.ignore();
    return 0;
    }
    Now i'll point somethings i changed:

    • changed the declaration of dollar variable to be double as well because of the later calculations.
    • put the part where you ask for input in a while loop to prevent you from having negative change.
    • Notice the -= operator, x -= y; does the exacte same thing as x = x - y;
    • changed the for statements because if you want to access the variables at the end of the program you must declare the variables outside the for statement. Added to that i removed the assignment to such variable as i assign it the required value on the line before (initializing a variable to some value is less expensive than initializing and later assignment i've heard)
    • I decided it would be better to use the defined value of the dollar,halfDollar, etc... values for the change computations instead of using hardcoded values like you had.
    Anyway, this might not be perfect but from what i've tried at least it runs and seems to do what you're after. Don't just take the code and use it without ever looking at it again, try to see why i've changed what i've changed and see if you can learn with it, that's the purpose of me posting the code.

    Hope this has helped somewhat. Cheers

  4. #4
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    <EDIT: this applies to original code only>
    It doesn't compile. The reason is that all the variables you declare in your for() loops are local in scope to the loop; yet you try to use them at the end of the program.



    For another thing, using doubles for dollar amounts seems to be a Really Bad Idea™ to me. It's probably the reason your pennies part is fouling up.

    The thing is, doubles can't represent 1/100 ie the cent values accurately. More or less accurate to, say, 0.00000000001017.

    You *could* deal with complicated stuff like EPSILON, or make your own USDollar class or something, OR simply read in entire lines with getline(), get the numbers out of it and store them as seperate dollar/cent values.
    Last edited by jafet; 04-08-2006 at 11:12 AM.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    The thing is, doubles can't represent 1/100 ie the cent values accurately.
    doubles are accurate to DBL_DIG digits (defined in <float.h>). DBL_DIG is usually 15. .0001 requires far less than 15 digits to store (if your dollar value is small).

    I usually store monetary values in an int, multiplying "12.34" by 100 and storing it as "1234".
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    Quote Originally Posted by me!
    You *could* deal with complicated stuff like EPSILON, or make your own USDollar class or something
    Example:
    Code:
    #include <iostream>
    #include <string>
    #include <sstream>
    
    class usdollar
    {
    	friend usdollar operator-(usdollar);
    	friend std::ostream &operator<<(std::ostream&, usdollar);
    	friend std::istream &operator<<(std::istream&, usdollar&);
    	friend bool operator>(usdollar, usdollar);
    	friend bool operator<(usdollar, usdollar);
    	friend bool operator==(usdollar, usdollar);
    	friend usdollar operator+(usdollar, usdollar);
    	friend usdollar operator-(usdollar, usdollar);
    	friend usdollar operator*(usdollar, double);
    	friend usdollar operator/(usdollar, double);
    	
    	protected:
    		int dollaramount;
    		int centamount;
    		int sign;
    	
    	public:
    		//variables
    		
    		//constructors
    		usdollar(double amount)
    		{
    			this -> init(amount);
    		}
    		usdollar(int dollars = 0, int cents = 0)
    		{
    			this -> init(dollars, cents);
    		}
    		//various assignment operators
    		//all return itself for use in chained expressions
    		usdollar operator=(usdollar u1)
    		{
    			this -> dollaramount = u1.dollaramount;
    			this -> centamount = u1.centamount;
    			this -> sign = u1.sign;
    			return *this;
    		}
    		//dirty-work functions
    		void init(double amount)
    		{
    			//we take EPSILON to be 1e-9 here, should be enough
    			this -> init((int)amount, (int)((amount + 0.000000001 - (int)amount) * 100));
    		}
    		void init(int dollars = 0, int cents = 0)
    		{
    			this -> sign = 1;
    			this -> dollaramount = dollars;
    			this -> centamount = cents;
    		}
    		void rationalize()
    		{
    			this -> dollaramount += this -> centamount / 100;
    			this -> centamount %= 100;
    			
    			while(this -> centamount < 0)
    			{
    				this -> dollaramount--;
    				this -> centamount += 100;
    			}
    			
    			if(this -> dollaramount < 0)
    			{
    				this -> sign *= -1;
    				this -> dollaramount = -this -> dollaramount;
    				this -> centamount = -this -> centamount;
    				
    				this -> rationalize();
    			}
    		}
    		
    		//return double value
    		double getd()
    		{
    			return this -> sign * (this -> dollaramount + this -> centamount / 100.0);
    		}
    		//return sign
    		int gsign()
    		{
    			return this -> sign;
    		}
    };
    //unary minus
    usdollar operator-(usdollar u1)
    {
    	u1.sign *= -1;
    	return u1;
    }
    
    //input and output operators
    std::istream &operator>>(std::istream &in, usdollar &u1)
    {
    	double temp;
    	in >> temp;
    	
    	u1.init(temp);
    	return in;
    }
    std::ostream &operator<<(std::ostream &out, usdollar u1)
    {
    	if(u1.sign == -1)
    	{
    		out << "-";
    	}
    	out << "$" << u1.dollaramount << ".";
    	if(u1.centamount < 10)
    	{
    		out << "0";
    	}
    	out << u1.centamount;
    	return out;
    }
    //larger than?
    bool operator>(usdollar u1, usdollar u2)
    {
    	//compare dollaramounts first
    	if(u1.dollaramount > u2.dollaramount)
    	{
    		return true;
    	}
    	if(u1.dollaramount < u2.dollaramount)
    	{
    		return false;
    	}
    	//dollaramounts are eqaul, compare centamounts
    	if(u1.centamount > u2.centamount)
    	{
    		return true;
    	}
    	if(u1.centamount <= u2.centamount)
    	{
    		return false;
    	}
    }
    //smaller than?
    bool operator<(usdollar u1, usdollar u2)
    {
    	//compare dollaramounts first
    	if(u1.dollaramount < u2.dollaramount)
    	{
    		return true;
    	}
    	if(u1.dollaramount > u2.dollaramount)
    	{
    		return false;
    	}
    	//dollaramounts are eqaul, compare centamounts
    	if(u1.centamount < u2.centamount)
    	{
    		return true;
    	}
    	if(u1.centamount >= u2.centamount)
    	{
    		return false;
    	}
    }
    //equality
    //unneeded (compiler provides default), but given anyway
    bool operator==(usdollar u1, usdollar u2)
    {
    	return ((u1.dollaramount == u2.dollaramount) && (u1.centamount == u2.centamount));
    }
    //addition
    usdollar operator+(usdollar u1, usdollar u2)
    {
    	u1.dollaramount += u2.dollaramount;
    	u1.centamount += u2.centamount;
    	//rationalize
    	u1.rationalize();
    	return u1;
    }
    //subtraction
    usdollar operator-(usdollar u1, usdollar u2)
    {
    	u1.dollaramount -= u2.dollaramount;
    	u1.centamount -= u2.centamount;
    	//rationalize
    	u1.rationalize();
    	return u1;
    }
    //and...
    usdollar operator*(usdollar u1, double n)
    {
    	//rationalize
    	u1.init(u1.sign * (u1.dollaramount + u1.centamount / 100.0) * n);
    	return u1;
    }
    usdollar operator/(usdollar u1, double n)
    {
    	//rationalize
    	u1.init(u1.sign * (u1.dollaramount + u1.centamount / 100.0) / n);
    	return u1;
    }
    //complex operators
    //reuse previous operators
    bool operator>=(usdollar u1, usdollar u2)
    {
    	return ((u1 > u2) || (u1 == u2));
    }
    bool operator<=(usdollar u1, usdollar u2)
    {
    	return ((u1 < u2) || (u1 == u2));
    }
    usdollar &operator+=(usdollar &u1, usdollar u2)
    {
    	u1 = u1 + u2;
    	return u1;
    }
    usdollar &operator-=(usdollar &u1, usdollar u2)
    {
    	u1 = u1 - u2;
    	return u1;
    }
    usdollar &operator*=(usdollar &u1, double n)
    {
    	u1 = u1 * n;
    	return u1;
    }
    usdollar &operator/=(usdollar &u1, double n)
    {
    	u1 = u1 / n;
    	return u1;
    }
    
    //main()
    int main()
    {
    	using namespace std;
    	
    // self documenting code begin
    	cout << "This program calculates the amount of change\ngiven back after a purchase\n\n";
    // self documening code end
    	cout << "Enter the purchase amount: $";
    	usdollar purchase;
    	cin >> purchase;
    	cout << "Enter the amount of money given: $";
    	usdollar money;
    	cin >> money;
    	cout << "\n\n";
    	
    	usdollar change = money - purchase;
    	
    	//if negative
    	if(change < 0)
    	{
    		cout << "Not enough money! Customer still owes " << change << "!\n";
    	}
    	else if(change == 0)
    	{
    		cout << "Customer has paid exact amount! No need to return change!\n";
    	}
    	//calculate change
    	else
    	{
    		//various denominations
    		usdollar denominations[] = {
    			1000.00,
    			500.00,
    			100.00,
    			50.00,
    			20.00,
    			10.00,
    			5.00,
    			1.00,
    			0.50,
    			0.25,
    			0.10,
    			0.05,
    			0.01
    		};
    		//temp counting array
    		int count[13] = {0};
    		//pluran and singular currencies
    		string namepl[] = {
    			"grand",
    			"five hundred dollars",
    			"hundred dollars",
    			"fifty dollars",
    			"twenty dollars",
    			"ten dollars",
    			"five dollars",
    			"dollars",
    			"half dollars",
    			"quarters",
    			"dimes",
    			"nickels",
    			"pennies"
    		};
    		string namesg[] = {
    			"grand",
    			"five hundred dollars",
    			"hundred dollars",
    			"fifty dollars",
    			"twenty dollars",
    			"ten dollars",
    			"five dollars",
    			"dollar",
    			"half dollar",
    			"quarter",
    			"dime",
    			"nickel",
    			"penny"
    		};
    		int length = 13;
    		
    		//for each denomination
    		for(int i = 0; i < length; ++i)
    		{
    			//compute change
    			for(count[i] = 0; change >= denominations[i]; ++count[i])
    			{
    				change -= denominations[i];
    			}
    		}
    	
    		 // Self documenting output to screen
    		cout << "\nPlease give the customer "  << money - purchase << " back in change:\n";
    		for(int i = 0; i < length; ++i)
    		{
    			//if >1 cout plural
    			if(count[i] > 1)
    			{
    				cout << count[i] << " " << namepl[i] << "\n";
    			}
    			//if ==1 cout singular
    			if(count[i] == 1)
    			{
    				cout << count[i] << " " << namesg[i] << "\n";
    			}
    			//if ==0 then skip
    		}
    	}
    	cout << "\n\n";
    	system("pause");
    	return 0;
    }
    Hmm I feel a tingling sense of accomplishment...
    Last edited by jafet; 04-08-2006 at 12:15 PM.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  7. #7
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    doubles are accurate to DBL_DIG digits
    True, but they don't provide PURE precision, because not all decimal fractions can be handled nicely in binary.

    I usually store monetary values in an int, multiplying "12.34" by 100 and storing it as "1234".
    What if I, a billionaire, wanted to enter $1234567890.12? The integer would overflow.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  8. #8
    Registered User
    Join Date
    Aug 2005
    Posts
    28
    jafet, thats some awesome code there ;-) I will be using it to get as an example for some other things I need to learn how to do.

    I think dwks answered the simple question. Doubles can't work with decimal numbers correctly, so I have made a few mod's to my code and now it's working as it should. I multiplied the purchase and money by 100 and then worked to zero. It no longer fails. Thanks!

    Here is an exerpt of code I settled on:

    Code:
                    double purchase;
    	double money;
    	double change;
    	int difference;
    	int dollar = 100;
    	int halfDollar = 50;
    	int quarter = 25;
    	int dime = 10;
    	int nickel = 5;
    	int penny = 1;
    
    	
    		cout << "This program calculates the amount of change\ngiven back after a purchase";
    		cout << "\nEnter the purchase amount:  ";
    		cin >> purchase;
    		purchase = purchase * 100; // GETS RID OF THE DECIMAL
    		cout << "\nEnter the amount of money given:  ";
    		cin >> money;
    		money = money * 100; //GETS RID OF THE DECIMAL
    		change = money - purchase;
    		difference = change; // puts the integer variable into play
    		change = change / 100; //converts change back to decimal for display
    		cout << difference <<"  DEBUGGING LOGIC - before we begin\n"; // for debugging
    Last edited by kryonik; 04-08-2006 at 03:24 PM.

  9. #9
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,434
    *shrug*
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Non-blocking socket connection problem
    By cbalu in forum Linux Programming
    Replies: 25
    Last Post: 06-03-2009, 02:15 AM
  2. fail to count digit of an integer (fail at 9)
    By azsquall in forum C++ Programming
    Replies: 3
    Last Post: 05-02-2008, 09:42 AM
  3. bad and fail of steam
    By George2 in forum C++ Programming
    Replies: 8
    Last Post: 02-19-2008, 02:07 AM
  4. Reasons as to why fread would fail
    By Happy_Reaper in forum C Programming
    Replies: 4
    Last Post: 04-08-2006, 11:41 AM
  5. Set fail flag in istream
    By *ClownPimp* in forum C++ Programming
    Replies: 0
    Last Post: 03-20-2003, 08:24 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21