简体   繁体   中英

Python counting through a number with >=

I'm learning Python(2.7) at the moment, and an exercise says to write a program which counts how many coins you need to pay a specific sum. My solution is this:

sum = input("Bitte gebe einen Euro Betrag ein: ")
coins = []
euro = [20,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01]

for i in euro:
    while sum >= i:
        sum -= i
        coins.append(i)

print coins

This is nearly working, but when I input eg 17,79 it gives me the coins for 17,78.

Bitte gebe einen Euro Betrag ein: 17.79
[10, 5, 2, 0.5, 0.2, 0.05, 0.02, 0.01]

Why? Has this something to do with round?

For currency calculations it's best to avoid float type if you can, because of accumulating rounding errors. You can do it in a way similar to this:

amount= input("Bitte gib einen Euro Betrag ein: ")
coins = []
cents = [2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1]
amount = int(float(amount) * 100)
for cent in cents:
    while amount >= cent:
        amount -= cent
        coins.append(cent)

print [coin / 100.0 for coin in coins]

I've also changed the variable name from sum to amount - sum will shadow the sum built-in function.

Result:

Bitte gebe einen Euro Betrag ein: 17.79
[10.0, 5.0, 2.0, 0.5, 0.2, 0.05, 0.02, 0.02]

Alternatively, you can implement this without inner while loop, like this:

for cent in cents:
    n = int(math.floor(amount / cent))
    amount -= n * cent
    coins += [cent] * n

It's possible to exit loop earlier ( if not amount: break ) and avoid unnecessary operations ( if not n: continue ), but I omitted these guards for readability.

Another possible alternative is to use the decimal data type.

It has. If after executing the code you check the 'sum' value, you get something like 0,009999999999999133, which IS smaller than the smallest coin.

My suggestion? Do everything in cents!

sum = int(input("Your text") * 100)
cents = [2000,1000,500,200,100,50,20,10,5,2,1]
coins = []

for i in euro:
    while True:
        if i <= sum:
            coins.append(i)
            sum -= i
        else:
            break

for i in range(len(coins)):
    coins[i] /= 100

print(coins)

This is a problem related to float accuracy. After the calculation, I get:

sum == 0.009999999999999133

ie slightly less than one Euro cent (note, you shouldn't call it sum because then you shadow the built-in sum function and can't use eg sum(coins) to get the total). You can fix this with a tolerance approach, replacing

while sum >= i:

with

while (sum - i) > -0.001: # allow for slight inaccuracy

Similarly, it is best to compare floats using a tolerance, instead of:

if a == b:

use

if abs(a - b) < tolerance:

Indeed, as was pointed out, this seems to be a rounding problem, since the algorithm (for this set of coins!) is correct. If you store the coins as integers in cents, the correct solution is calculated:

s = input("Bitte gebe einen Euro-Cent Betrag ein: ")
coins = []
euro = [2000,1000,500,200,100,50,20,10,5,2,1]

for i in euro:
    while s >= i:
        s -= i
        coins.append(i)
print coins

Output:

Bitte gebe einen Euro-Cent Betrag ein: 1779
[1000, 500, 200, 50, 20, 5, 2, 2]

Btw, I would recommend not to use sum as a variable name since it is the name of a built-in function.

@BartoszKP pointed out that it's best to avoid using float and because you might end up with some nasty decimals that you won't like. So you might want to use round , with minimal changes to your code, you can do this:

sum = input("Bitte gebe einen Euro Betrag ein: ")
coins = []
euro = [20,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01]

for i in euro:
    while sum >= i:
        sum -= round(i,2)
        coins.append(i)

if sum > 0:
    coins.append(round(sum,2))

print coins

[out:]

Bitte gebe einen Euro Betrag ein: 19.99
[10, 5, 2, 2, 0.5, 0.2, 0.2, 0.05, 0.02, 0.01, 0.01]

But this is NOT the optimal solution since since you would want this instead ;)

Bitte gebe einen Euro Betrag ein: 19.99
[10, 5, 2, 2, 0.5, 0.2, 0.2, 0.05, 0.02, 0.02]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM