1

A friend and I coded these two functions to answer a problem of how many coins you would need to give back for change if given the total value of the change. Quarters, dimes, nickels, and pennies:

The magnitude of our change values are giving us different answers, however I was unsure how to explain this difference

def num_coins(cents):
    coins = [25, 10, 5, 1]
    count = 0
    for coin in coins:
        while cents >= coin:
            cents = cents - coin
            count += 1

    return count

#########

def coin_return(change):

    coin_options = [.25,.10,.05,.01]
    number_of_coins = 0

    for coin in coin_options:
        while change >= coin:
            number_of_coins += 1
            change = change - coin

    return number_of_coins

print(coin_return(.24))
print(num_coins(24))

The right output is six, two dimes and four pennies. The num_coins function returns this, however the coin_return function returns five. What's happening here? Am I missing something obvious?

  • 2
    Calculations done in floating point numbers cannot be tested for equality. When you expect `.01` the computer may have the value `.0099999`, for example. – Chris Charley Jul 30 '19 at 22:49
  • Never use `float`s when needing an exact (to the last decimal) value. Due to their computer representation they will not be exact. – JohanL Jul 30 '19 at 22:49
  • 1
    Possible duplicate of [What is the best way to compare floats for almost-equality in Python?](https://stackoverflow.com/questions/5595425/what-is-the-best-way-to-compare-floats-for-almost-equality-in-python) – norok2 Jul 30 '19 at 23:06

1 Answers1

1

As others have already pointed out in the comments, the issue is float approximation, as you can see from the code below:

def num_coins(cents, coins):
    count = 0
    for coin in coins:
        while cents >= coin:
            print(cents)
            cents = cents - coin
            count += 1
    return count

Used with int (exact):

print(num_coins(24, [25, 10, 5, 1]))
Cents: 24
Cents: 14
Cents: 4
Cents: 3
Cents: 2
Cents: 1
6

used with float:

print(num_coins(.24, [0.25, 0.10, 0.05, 0.01]))
Cents: 0.24
Cents: 0.13999999999999999
Cents: 0.03999999999999998
Cents: 0.029999999999999978
Cents: 0.019999999999999976
5

you could work around this with the round() function, e.g.:

def num_coins(cents, coins, precision):
    count = 0
    for coin in coins:
        while round(cents, precision) >= round(coin, precision):
            cents = cents - coin
            count += 1
    return count


print(num_coins(.24, [0.25, 0.10, 0.05, 0.01], 2))
# 6
print(num_coins(24, [25, 10, 5, 1], 0))
# 6

Another way would be to use math.isclose():

import math


def num_coins(cents, coins):
    count = 0
    for coin in coins:
        while cents > coin or math.isclose(cents, coin):
            cents = cents - coin
            count += 1
    return count


print(num_coins(.24, [0.25, 0.10, 0.05, 0.01]))
# 6
print(num_coins(24, [25, 10, 5, 1]))
# 6

Alternatively, you could stick to int or use the decimal module from the standard library.

norok2
  • 25,683
  • 4
  • 73
  • 99