0

I'm a beginner python programmer and i'm wondering why this script won't work when inputted a float of 0.30. I've tried other inputs (i.e 0.50, 1.00, 0.10 etc...) and they worked fine. There may be simpler ways to do this calculator, but I just want to know why this script in particular won't work. The script is the following:

money = float(raw_input("Input the money: "))
twofive_count = 0
ten_count = 0
five_count = 0
one_count = 0
while money != 0.00:
    if money >= 0.25:
        money -= 0.25
        twofive_count +=1
    elif money < 0.25 and money >= 0.10:
        money -= 0.10
        ten_count += 1
    elif money < 0.10 and money >= 0.05:
        money -= 0.05
        five_count += 1
    elif money < 0.05 and money >= 0.01:
        money -= 0.01
        one_count += 1
print "Quarters:",twofive_count
print "Dimes:",ten_count
print "Nickels:",five_count
print "Pennies:",one_count
total_change = twofive_count + ten_count + five_count + one_count
print "Total number of coins in change:",total_change
ObesePlant
  • 15
  • 6
  • 2
    take a look at http://stackoverflow.com/questions/588004/is-floating-point-math-broken – user3288829 Aug 11 '15 at 01:34
  • print "money" at the bottom of the while loop, i.e. what happens when it equals 1 cent --> elif money < 0.05 and money >= 0.01: And the while loop should be money > 0 because floats are inaccurate and the result may be slightly less than zero –  Aug 11 '15 at 01:37

4 Answers4

3

The issue occurs because of how internal representation of float works, when you do -

0.30 - 0.25

You get a result as -

0.04999999999999999

And when you subtract 0.05 from this, you get a negative number not a 0.00 . Example to show this -

>>> s = float('0.30')
>>> s
0.3
>>> s-0.25
0.04999999999999999
>>> s-0.05
0.25
>>> s = s-0.25
>>> s = s - 0.05
>>> s
-1.3877787807814457e-17

I think since you are dealing with currencies, you can round the number to 2 decimal places at all times, and it should be fine.

Example -

money = float(raw_input("Input the money: "))
twofive_count = 0
ten_count = 0
five_count = 0
one_count = 0
while money != 0.00:
    if money >= 0.25:
        money = round(money - 0.25, 2)
        twofive_count +=1
    elif money < 0.25 and money >= 0.10:
        money = round(money - 0.10, 2)
        ten_count += 1
    elif money < 0.10 and money >= 0.05:
        money = round(money - 0.05, 2)
        five_count += 1
    elif money < 0.05 and money >= 0.01:
        money -= round(money - 0.01, 2)
        one_count += 1
print "Quarters:",twofive_count
print "Dimes:",ten_count
print "Nickels:",five_count
print "Pennies:",one_count
total_change = twofive_count + ten_count + five_count + one_count
print "Total number of coins in change:",total_change

Or if you do not want to round , you can use decimal.Decimal , in that case you would need to change all elements (to Decimal) , Example -

from decimal import Decimal
money = Decimal(raw_input("Input the money: "))
twofive_count = 0
ten_count = 0
five_count = 0
one_count = 0
while money != 0.00:
    if money >= Decimal('0.25'):
        money -= Decimal('0.25')
        twofive_count +=1
    elif money < Decimal('0.25') and money >= Decimal('0.10'):
        money -= Decimal('0.10')
        ten_count += 1
    elif money < Decimal('0.10') and money >= Decimal('0.05'):
        money -= Decimal('0.05')
        five_count += 1
    elif money < Decimal('0.05') and money >= Decimal('0.01'):
        money -= Decimal('0.01')
        one_count += 1
print "Quarters:",twofive_count
print "Dimes:",ten_count
print "Nickels:",five_count
print "Pennies:",one_count
total_change = twofive_count + ten_count + five_count + one_count
print "Total number of coins in change:",total_change
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
3

Forget floating point, that way lies madness if you don't understand what's going on under the covers.

If you want exactness, turn the value into an integer as soon as possible:

money = float(raw_input("Input the money: "))

money = int (money * 100 + 0.1)           # Make integral pennies
                                          #   avoiding 0.999999 problems
twofive_count = 0
ten_count = 0
five_count = 0
one_count = 0
while money > 0:
    if money >= 25:                       # Make sure you use pennies
        money -= 25
        twofive_count +=1
    elif money >= 10:
        money -= 10
        ten_count += 1
    elif money >= 5:
        money -= 5
        five_count += 1
    elif money >= 1:
        money -= 1
        one_count += 1

print "Quarters:",twofive_count
print "Dimes:",ten_count
print "Nickels:",five_count
print "Pennies:",one_count
total_change = twofive_count + ten_count + five_count + one_count
print "Total number of coins in change:",total_change

You'll also notice I've cleaned up your coin detection code. There is no need to check both ends of the range (e.g., less than a nickel and at least a penny) because you're using elif which means the first part of that condition has already been checked.


Of course, there's often a more efficient way to do it if you think about it a bit. A first step would be breaking each step into its own while to isolate each coin count calculation, something like:

while money >= 25:
    money -= 25
    twofive_count +=1
while money >= 10:
    money -= 10
    ten_count += 1
while money >= 5:
    money -= 5
    five_count += 1
while money >= 1:
    money -= 1
    one_count += 1

From there, it's a short step to realising that, once you've worked out all non-penny values, the number of pennies can be done quicker:

while money >= 25:
    money -= 25
    twofive_count +=1
while money >= 10:
    money -= 10
    ten_count += 1
while money >= 5:
    money -= 5
    five_count += 1
one_count = money

But there's also a way to figure out each coin count without repeated subtraction, since repeated subtraction is exactly why division was invented :-)

twofive_count = int (money / 25)
money -= (twofive_count * 25)

ten_count = int (money / 10)
money -= (ten_count * 10)

five_count = int (money / 5)
money -= (five_count * 5)

one_count = money
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

As said by others, floating point representation is not precise. To use more precise decimal representation use fixed point notation with the Decimal class from the decimal Python module[0].

[0] https://docs.python.org/3/library/decimal.html

Camilo Torres
  • 478
  • 2
  • 8
0

I think your problem is while money != 0.00:

Comparing floats is fraught with danger as binary representation of fractions aren't perfect. To compare a float properly you need to subtract one from the other and then see if the result is within some tolerance value which is reasonable for your application.

I think using the decimal class would solve your problem and provide a much more sensible solution than trying to make floats work for you.

https://docs.python.org/2/library/decimal.html

From the page:

  • Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.

  • The exactness carries over into arithmetic. In decimal floating point, 0.1 + 0.1 + 0.1 - 0.3 is exactly equal to zero. In binary floating point, the result is 5.5511151231257827e-017. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.

Dominique McDonnell
  • 2,510
  • 16
  • 25