Alexander Smith
Alexander Smith

Reputation: 65

Change calculator only works if one type of coin needed

I'm currently trying to learn python and have been going through beginner projects on /r/learnpython. My idea for the change calculator project was to create a dictionary with keys 'quarter', 'dime', 'nickel', and 'penny', each with values initialized to 0. My code, shown below, appears to only work when the change I input only requires one type of coin, i.e. 0.75 --> 3 quarters, 0.1 --> 1 dime, etc.

 change_map = {
    'quarter' : 0,
    'dime' : 0,
    'nickel' : 0,
    'penny' : 0
}

def calculator(change):
    while change > 0:
        if change >= 0.25:
            change -= 0.25
            change_map['quarter'] += 1
        elif change < 0.25 and change >= 0.10:
            change -= 0.10
            change_map['dime'] += 1
        elif change < 0.10 and change >= 0.05:
            change -= 0.05
            change_map['nickel'] += 1
        elif change < 0.05 and change >= 0.01:
            change -= 0.01
            change_map['penny'] += 1
    print "You need the following: "
    print change_map

change = raw_input("Please enter amount of change: ")
change = float(change)
calculator(change)

Upvotes: 4

Views: 181

Answers (2)

Olivier Melan&#231;on
Olivier Melan&#231;on

Reputation: 22314

Floating point arithmetic error

Your error is due to float arithmetic error. Here is what happens when you input a value such as 0.26.

change = 0.26
change  -= 0.25
change  -= 0.01
print (change) # 8.673617379884035e-18

Since the last value of change is above 0 but below 0.01, you enter an infinite loop.

How to fix it

One way to fix this is to rely on exact arithmetic by using int instead of float to represent discrete values such as currencies. This means making your base unit the cent instead of the dollar.

change_map = {
    'quarter' : 0,
    'dime' : 0,
    'nickel' : 0,
    'penny' : 0
}

def calculator(change):
    while change > 0:
        if change >= 25:
            change -= 25
            change_map['quarter'] += 1
        elif change >= 10:
            change -= 10
            change_map['dime'] += 1
        elif change >= 5:
            change -= 5
            change_map['nickel'] += 1
        else:
            change -= 1
            change_map['penny'] += 1

    print ("You need the following: ")
    print (change_map)

change = raw_input("Please enter amount of change: ")

# Here we convert the decimal value input by the user to cents
change = int(float(change) * 100)

calculator(change)

Example:

Please enter amount of change: 0.26
You need the following: 
{'quarter': 1, 'dime': 0, 'nickel': 0, 'penny': 1}

Improvements

On a side note, you can improve your solution by using a dict of values and names for coins. In particular, this allows you to extend your program by updating the dict instead of having to add a new if-statement.

Here is an example that adds in the possibility to return a dollar as change.

value_map = {
    100: 'dollar',
    25: 'quarter',
    10: 'dime',
    5: 'nickel',
    1: 'penny'
}

def calculator(change):
    change_map = {}

    for value in sorted(value_map, reverse=True):
        coin = value_map[value]
        change_map[coin], change = divmod(change, value)

    print ("You need the following: ")
    print (change_map)

change = raw_input("Please enter amount of change: ")

change = int(float(change) * 100)

calculator(change)

Upvotes: 5

Kirill Korolev
Kirill Korolev

Reputation: 1006

I debugged your code and noticed that there was an infinite loop. Probably, that because of float arithmetics. You can declare an epsilon value like

eps = 1e-2

And change the while loop respectively

while change > eps

Upvotes: 2

Related Questions