0

i am tasked to make a program that will take a monetary amount and find the minimum number of coins needed to get that amount. here is my code.

import math

n1 = eval(input("Enter a monetary amount: "))

n1 = n1 * 100

dollars = 0
quarters = 0
dimes = 0
nickels = 0
pennies = 0

dollars = n1 / 100
n1 %= 100

quarters = n1 / 25 
n1 %= 25

dimes = n1 / 10 
n1 %= 10

nickels = n1 / 5 
n1 %= 5

pennies = n1


print (int(dollars), int(quarters), int(dimes), int(nickels), int(pennies))

whenever I enter a number that needs nickels, it doesn't count them. for example, the output for 1.05 would be

1 0 0 0 0

the output for 1.15 is

1 0 1 0 4

any hints would be appreciated, thanks.

edited a typo that i had, code is still not working as intended though.

  • Writing a solution that works on any monetary system is tricky, if you have values like 10, 7, 5 and 1. If you want to get the best configuration for 12, you can't just use the biggest one and carry on, because that would yield a result of `1*10 2*1` using 3 coins, although you can do it with 2: `1*7 1*5`. I'll try to write such a solution anyways, *because* it is tricky. – CodenameLambda May 03 '16 at 16:35
  • 3
    Why use `eval` instead of `int` or `float` ? – Kevin M Granger May 03 '16 at 16:36
  • 1
    @KevinMGranger I'd assume it passed through the `2to3` script as it changes python2's `input(...)` to `eval(input(..))` – Tadhg McDonald-Jensen May 03 '16 at 16:38
  • 2
    I can't reproduce that behaviour, can you add `print(repr(n1))` in between each step? I have a feeling float operations are responsible for this. – Tadhg McDonald-Jensen May 03 '16 at 16:41
  • its giving me 14.999... and so on instead of 15, 5, etc. im not sure why or how to fix it – user24580807245 May 03 '16 at 16:43
  • 2
    yep, floats operations are to blame, I'd recommend switching out `eval` for `decimal.Decimal` and seeing if that solves your problem, either that or get the user to input the number in cents and skip the `n1 * 100` step, or using `round` – Tadhg McDonald-Jensen May 03 '16 at 16:45
  • decimal.Decimal worked. thanks a lot – user24580807245 May 03 '16 at 16:48
  • 1
    Possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Rob Watts May 03 '16 at 16:49

4 Answers4

1

You're running into a floating point issues:

>>>> 1.15*100
114.99999999999999

As you can see, here you clearly do not have 115 cents. You have just under that. So you use one dollar, one dime, and 4.99999 pennies (int rounds it down to four).

The easiest way to fix it is to have the user give you an integer number of cents so that you can work in cents the entire time, or to use the built-in round function to get rid of floating point errors.

Rob Watts
  • 6,866
  • 3
  • 39
  • 58
  • I agree with Rob. For completeness, when you need to deal with more involved processing on decimals, including currency, check out the decimal library: https://docs.python.org/2.7/library/decimal.html – ViennaMike May 03 '16 at 17:02
1

You can refer to Is floating point math broken? for a more comprehensive explanation on what is going on but basically when you type 1.05 into your code (or through an eval) it does not store the exact value you might expect:

>>> (1.05).as_integer_ratio()
(4728779608739021, 4503599627370496)

If you want the computer to store the exact decimal representation of the number you can simply use decimal.Decimal for the intermediate step:

n1 = decimal.Decimal(input("Enter a monetary amount: "))

n1 = int(n1 * 100) #now you won't get rounding issues

alternately you can parse the number entered yourself to remove the decimal and skip the math required to compensate all togther:

def dollar_to_cent(s):
    n,_,end = s.partition(".")
    if not all(i=="0" for i in end[2:]):
        raise ValueError("can only have up to two digits after decimal.")
    return int("{}{:0<2}".format(n,end[:2]))

>>> dollar_to_cent("1")
100
>>> dollar_to_cent("2.")
200
>>> dollar_to_cent("2.3")
230
>>> dollar_to_cent("2.05")
205
>>> dollar_to_cent("2.050000")
205
>>> dollar_to_cent("2.001")
Traceback (most recent call last):
   ...
ValueError: can only have up to two digits after decimal.
Community
  • 1
  • 1
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
0

Looks like a typo: nickels vs nickles

Edit: now that you've fixed the typo, it looks like it's definitely a rounding issue. Since you're converting from dollars to a whole number of cents, try turning it into an integer before doing any operations.

Change your n1 = n1 * 100 line to n1 = int(round(n1 * 100)). I tried this out on my computer and it seemed to work.

Justin Buchanan
  • 404
  • 3
  • 9
0

It is best to work with cents all the way for these kind of problems. Try to make 105 cents (integer) instead of 1.05 times 100. You can avoid rounding all together. Further, since you care about "remainder", use modulo operator instead of division.

I'd solve it like this:

cents = 115
remainder = cents%25
nickels = (cents - remainder)/25

cents = remainder
remainder = cents%10
dimes = (cents - remainder)/10

...

and so on.

However, probably not the question you asked but in general cases this problem is NP-hard, and further depending on the coin denominations some change is not makeable.

user1669710
  • 224
  • 1
  • 11
  • `n1 %= 100` OP *is* using the modulo operator. – Rob Watts May 03 '16 at 17:03
  • True; sorry about the wording; I meant use "division" after "modulo" to avoid floating points. to be sure about divisibility, and don't do the first multiplication n1*100. – user1669710 May 03 '16 at 17:07