Reputation:
I'm writing a programme to calculate change for a customer transaction that will also tell the cashier exactly how many of each denomination to hand the customer (although it assumes an infinitely filled till).
It seems to all be in order and working, except for a few example and I can't work out why. For example, when I type in $5.65 as the amount due, and $6.00 as the amount given, it calculates the change as:
1 x $0.2
1 x $0.1
2 x $0.02
which is clearly not right. It seems to be skipping over the fact that it needs to give back a 5 cent piece, rather than 2 * 2 cent pieces. What is going on here?
Here is my source code:
def change():
due = float(raw_input("Amount Due: $"))
paid = float(raw_input("Amount Paid: $"))
change = float(paid - due)
print "\nChange due: $%.2f" % (change)
print "\nHand the customer: "
denom = (20.00, 10.00, 5.00, 2.00, 1.00, 0.50, 0.20, 0.10, 0.05, 0.02, 0.01)
change_due = [" "]*len(denom)
amount = change
while amount > 0:
for i in range(len(denom)):
change_due[i] = int(amount/denom[i])
amount = amount%denom[i]
if change_due[i] > 0:
print "\n" + str(change_due[i]) + " x " + "$" + str(denom[i])
break
change()
NOTE: the $ sign is only used because I can't figure out how to display a £ correctly in Python. So I've used sterling denominations in the "denom" tuple.
Upvotes: 1
Views: 2428
Reputation: 21609
As you now know floating point numbers are inappropriate for representing exact values. You may also choose to use the decimal module, which can exactly represent fractional values and is ideal for representing monetary values.
from decimal import Decimal
def change():
due = Decimal(raw_input("Amount Due: $"))
paid = Decimal(raw_input("Amount Paid: $"))
change = paid - due
print "\nChange due: $%.2f" % (change)
print "\nHand the customer: "
denoms = map(Decimal, ('20.00', '10.00', '5.00', '2.00', '1.00', '0.50', '0.20', '0.10', '0.05', '0.02', '0.01'))
remain = change
for denom in denoms:
thisdenom, remain = divmod(remain, denom)
if thisdenom > 0:
print "\n%d x $ %s" % (thisdenom, str(denom))
change()
Upvotes: 1
Reputation: 77857
Most important, you're using integer-specific operations on floating-point numbers. Most base-10 decimals do not represent perfectly in binary. Convert your program to work in integral pence (i.e. multiply all amounts by 100). For instance:
due = 595
paid = 600
change = paid - due
print "\nChange due: $%.2f" % (change)
print "\nHand the customer: "
denom = (2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1)
This fixed the logic and computational problems I had with your program. In the case you gave, your program was trying to give change for something like 0.049999987 pounds -- hence the pair of tuppence.
Upvotes: 5