Avoiding infinite loop in simple Python code [duplicate] - python

I am making a change program in python. The user must input a dollar amount and then the program will calculate the change in twenties, tens, fives, ones, quarters, dimes, nickels, and pennies. I was instructed to use the round function for the pennies because If I input an amount of $58.79, the program tells me to give 3 pennies back when it should be 4. Is there a way to round up these pennies?
I know the value of a penny is .01, but python reads this as .100000000001 which I believe is the problem.
Any help is appreciated, here is the section I need rounded:
# get the amount to change from the user
change = input("Please enter the amount to change: $")
print "To make change for $",change,"give the customer back:"
# calculate number of twenties
twenties = int(change/ 20)
print twenties, "twenties"
change = change - twenties *20
# calculate tens
tens = int(change / 10)
print tens, "tens"
change = change - tens *10
#calculate fives
fives = int(change / 5)
print fives, "fives"
change = change - fives *5
#calculate ones
ones = int(change / 1)
print ones, "ones"
change = change - ones * 1
#calculate quarters
quarters = int(change / .25)
print quarters, "quarters"
change = change - quarters * .25
#calculate dimes
dimes = int(change / .10)
print dimes, "dimes"
change = change - dimes * .10
#calculate nickels
nickels = int(change / .05)
print nickels, "nickels"
change = change - nickels * .05
#calculate pennies
pennies = int(change / .01)
print pennies, "pennies"

Multiply the user's inputed dollar value by 100, convert to int, and work in units of pennies.
Integer arithmetic is dead simple (and exact). Floating point arithmetic is tricky and forces you to use more brain cells :) . Save brain cells and work entirely in ints.

The problem is that 0.01 cannot be accurately represented as a binary floating point value (which is how normal floats are stored – this is true for any language, not just Python). So if you need exact values for dollars and cents, you can use the decimal module. That way you can be sure that your values will be rounded exactly.
Or (since Decimals might be overkill here), first multiply every dollar value by 100 (this is not the same as dividing by 0.01 for the above reasons!), convert to int, do your calculations, and divide by 100.

The problems you are having are a result of imprecise floating-point arithmetic. There is no way to precisely represent 0.01 in IEEE floating point. That is one reason not to use floats when working with currency.
You should use decimals or even integers, because you know there are at most 2 digits after the decimal point. In that case, just work with the amount in pennies.
On the problem itself, I think the easiest way to do it is convert your amount in dollars to the amount in pennies, then iterate through a predefined list of values containing listing the equivalent amount of pennies (in descending order) for each denomination:
def change(amount):
# this can be removed if you pass the amount in pennies
# rather than dollars
amount = int(round(amount*100))
values = [2000, 1000, 500, 100, 25, 10, 5, 1]
denom = ['twenties', 'tens', 'fives', 'ones', 'quarters', 'dimes', 'nickels', 'pennies']
for i in range(len(values)):
num = amount / values[i]
amount -= num * values[i]
print str(num) + " " + denom[i]
Now calling change(58.79) will print
2 twenties
1 tens
1 fives
3 ones
3 quarters
0 dimes
0 nickels
4 pennies
As seen on codepad.org

use the decimal package
http://docs.python.org/library/decimal.html
it is meant exactly for this kind of use case

>>> from math import ceil
>>> a = 58.79
>>> ceil(a % 0.05 * 100)
4.0
>>>
[edit]
Now that I think of it, might aswell just go with
>>> a = 58.79
>>> a*100 % 5
4.0

Related

How can I improve my coin change calculator so that the total is 1.41 instead of 1.4100000000000001? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Decimals to 2 places for money in Python 3
(5 answers)
Closed last year.
I am working on a change calculator that accepts five arguments(dollars, quarters, dimes, nickels, pennies) and calculates the total amount of change. When I put change.py in the command line followed by 1 1 1 1 1 I am supposed to get 1.41 as the total but I am getting 1.4100000000000001 instead.When I put in other numbers it works as it should. Can anyone help with this? Thank you!
enter code here
import sys
def change(dollars,quarters,dimes,nickels,pennies):
dollars = int(float(dollars))
quarters = int(float(quarters))
dimes = int(float(dimes))
nickels = int(float(nickels))
pennies = int(float(pennies))
total = (dollars * 1.00) + (quarters * .25) + (dimes *.10) + (nickels * .05) + (pennies * .01)
return total
round(total)
dollars = sys.argv[1]
quarters = sys.argv[2]
dimes = sys.argv[3]
nickels = sys.argv[4]
pennies = sys.argv[5]
total = change(dollars,quarters,dimes,nickels,pennies)
print('The total value of your change is ',(total))
This is called a floating-point error (see this question). A simple solution would be to just round your numbers:
return round(total, 2)

Why does my python code produce an infinite loop if the number is larger than or equal to 772000000000000?

I have a code that is supposed to produce the lowest monthly payment you need to make to payoff a balance within a year. It works perfectly for all numbers until (so far as I've tested) 772000000000000.
Here is the code (numbers I've tested are below with their results):
import time
balance = float(input("balance: "))
annualInterestRate = float(input("AIR: "))
# formulas for lower and higher binding for bisectional search
monthlyInterestRate = annualInterestRate / 12
lower = balance / 12
higher = (balance * (1 + monthlyInterestRate) ** 12) / 12
while True:
guess = ((higher - lower) / 2 + lower)
print('higher: %s' % higher)
print('lower: %s' % lower)
remaining = balance
for i in range(12):
unpaid = remaining - guess
remaining = unpaid + monthlyInterestRate*unpaid
if higher - lower <= .01 and remaining < 0:
result = lower
print("Lowest Payment: %s" % result)
break
elif higher - lower <= .01 and remaining >= 0:
result = higher
print("Lowest Payment: %s" % result)
break
elif remaining < -0.01:
higher = guess
print("remaining: %s" % remaining)
print(guess)
print('too high')
time.sleep(.5)
elif remaining > 0:
lower = guess
print("remaining: %s" % remaining)
print(guess)
print('too low')
time.sleep(.5)
As I said, this gives the correct result for every number I tested but then I tested 999999999999999 and I got an infinite loop, I narrowed down where the issues start happening by testing the following values all using .2 as the AIR, using different AIR can produce different but similar results depending on the number, but the following should give you a good idea of what's happening:
662000000000000 works
771999999999999 works
772000000000000 repeats higher and lower over and over again after some time
772100000000000 works
772200000000000 repeats higher and lower over and over again after some time
772300000000000 infinite loop
772400000000000 infinite loop
772500000000000 infinite loop
882100000000000 infinite loop
999999999999999 infinite loop
Feel free to try them yourself, I'm completely dumbfounded why this is happening?
If you use floats you have to consider that these cannot represent all possible decimal values. If the values get big enough the difference between two representable floating point values might just exceed your threshold. That leads to a situation where the bisection cannot progress because there is just no "middle" float between the values. For example with:
balance = float("772300000000000")
annualInterestRate = float("0.2")
It ends up in an infinite loop with:
higher: 70368815315719.6
lower: 70368815315719.58
So, let's examine this a bit:
>>> a = 70368815315719.6
>>> b = 70368815315719.58
>>> import numpy as np
>>> np.nextafter(a, 0) == np.float64(b)
True
>>> np.nextafter(b, np.inf) == np.float64(a)
True
So there's no float between a and b but:
>>> b - a
-0.015625
So this is bigger than your threshold. So nothing can change between loops which results in the infinite loop.
However, you can easily fix this by using an arbitary precision Fraction:
from fractions import Fraction
balance = Fraction("772300000000000")
annualInterestRate = Fraction("0.2")
... # rest of your code
All operations in your code preserve the Fraction (if you had used math functions or ** it could be different) and at least on my computer it eventually finishes with:
higher: 161683724083791631395206486083981108997/2297661589986627614146560
lower: 41391033365450653948925712865241263190149/588201367036576669221519360
Lowest Payment: 161683724083791631395206486083981108997/2297661589986627614146560
Note the / in the output which comes from the Fraction.

Coin Change Maker Python Program

I am in a beginner programming course. We must do an exercise where we make a change maker program. The input has to be between 0-99 and must be represented in quarters, dimes, nickles, and pennies when the input is divided down between the four. I wrote a code that involved loops and whiles, but he wants something more easy and a smaller code. He gave me this as a way of helping me along:
c=int(input('Please enter an amount between 0-99:'))
print(c//25)
print(c%25)
He told us that this was basically all we needed and just needed to add in the dimes, nickles, and pennies. I try it multiple ways with the dimes, nickles, and pennies, but I cannot get the output right. Whenever I enter '99', I get 3 for quarters, 2 for dimes, 1 for nickles, and 0 for pennies. If anyone would be able to help me, that would be wonderful!
I'm now sure about what you want to achieve. Using the modulo operator you could easily find out how many quarters, dimes, nickles and pennies.
Let's just say you input 99.
c=int(input('Please enter an amount between 0-99:'))
print(c//25, "quarters")
c = c%25
print(c//10, "dimes")
c = c%10
print(c//5, "nickles")
c = c%5
print(c//1, "pennies")
this would print out:
3 quarters
2 dimes
0 nickles
4 pennies
n = int(input("Enter a number between 0-99"))
q = n // 25
n %= 25
d = n // 10
n %= 10
ni = n // 5
n %= 5
c = n % 5
print(str(q) +" " + str(d) +" " + str(ni) + " " + str(c))
I hope this helps? Something like this but don't just copy it. Everytime you divide by 25 10 5 you must lose that part because it's already counted.At the end print what ever you want :).
The actual trick is knowing that because each coin is worth at least twice of the next smaller denomination, you can use a greedy algorithm. The rest is just implementation detail.
Here's a slightly DRY'er (but possibly, uh, more confusing) implementation. All I'm really doing differently is using a list to store my results, and taking advantage of tuple unpacking and divmod. Also, this is a little easier to extend in the future: All I need to do to support $1 bills is to change coins to [100, 25, 10, 5, 1]. And so on.
coins = [25,10,5,1] #values of possible coins, in descending order
results = [0]*len(coins) #doing this and not appends to make tuple unpacking work
initial_change = int(input('Change to make: ')) #use raw_input for python2
remaining_change = initial_change
for index, coin in enumerate(coins):
results[index], remaining_change = divmod(remaining_change, coin)
print("In order to make change for %d cents:" % initial_change)
for amount, coin in zip(results, coins):
print(" %d %d cent piece(s)" % (amount, coin))
Gives you:
Change to make: 99
In order to make change for 99 cents:
3 25 cent piece(s)
2 10 cent piece(s)
0 5 cent piece(s)
4 1 cent piece(s)
"""
Change Machine - Made by A.S Gallery
This program shows the use of modulus and integral division to find the quarters, nickels, dimes, pennies of the user change !!
Have Fun Exploring !!!
"""
#def variables
user_amount = float(input("Enter the amount paid : "))
user_price = float(input("Enter the price : "))
# What is the change ?? (change calculation)
user_owe = user_amount - user_price
u = float(user_owe)
print "Change owed : " + str(u)
"""
Calculation Program (the real change machine !!)
"""
# Variables for Calculating Each Coin !!
calculate_quarters = u//.25
# Using the built-in round function in Python !!
round(calculate_quarters)
print "Quarters : " + str(calculate_quarters)
u = u%0.25
calculate_dime = u//.10
round(calculate_dime)
print "Dime : " + str(calculate_dime)
u = u%0.10
calculate_nickels = u//.05
round(calculate_nickels)
print "Nickels : " + str(calculate_nickels)
u = u%0.5
calculate_pennies = u//.01
round(calculate_pennies)
print "Pennies : " + str(calculate_pennies
Code for the change machine works 100%, its for CodeHs Python
This is probably one of the easier ways to approach this, however, it can also
be done with less repetition with a while loop
cents = int(input("Input how much money (in cents) you have, and I will tell
you how much that is is quarters, dimes, nickels, and pennies. "))
quarters = cents//25
quarters_2 = quarters*25
dime = (cents-quarters_2)//10
dime_2 = dime*10
nickels = (cents-dime_2-quarters_2)//5
nickels_2 = nickels*5
pennies = (cents-dime_2-quarters_2-nickels_2)

Rounding in Python

Hi everyone I am currently doing a school project and even my teacher is stumped. In Canada the penny has been removed so now all purchases are rounded to either 0 or 5. For example 5.53 would become 5.55 and 5.52 would become 5.50. I am trying to get my program to round like this, but I can't figure out how. I know how to round to decimal places, but I don't know how to round to specifics like this. Any help would be appreciated!
Here is my code. The project is about making a program that a cashier would use in a coffee shop.
order = ['coffee', 'tea', 'hashbrown','jelly','cream','chocolate','glazed','sandwich','bagel','cookie','pannini']
quantity = ['0','0','0','0','0','0','0','0','0','0','0']
# coffee = $1
# Tea = $1.30
# hashbrown = $1.25
# all donuts = $1.50
# sandwich = $2.50
# bagel = $2
# cookie = $0.50
# pannini = $4
cashier = 1
total = 0
while cashier == 1:
print "What did the customer order?"
ordered = input ()
while ordered > 10 or ordered < 0:
print "Do you want to input a valid order?"
ordered = input ()
print "How many are being ordered?"
quantityorder = input ()
quantity[ordered] = quantityorder
print "Ordered",quantityorder,"",order[ordered],"!"
if ordered == 0:
ordered = 1.0
elif ordered == 1:
ordered = 1.30
elif ordered == 2:
ordered = 1.25
elif ordered == 3 or ordered == 4 or ordered == 5 or ordered == 6:
ordered = 1.50
elif ordered == 7:
ordered = 2.50
elif ordered == 8:
ordered = 2
elif ordered == 9:
ordered = 0.50
else:
ordered = 4.0
price = ordered * quantityorder
total = total + price
print "Anything else?"
cashier = input () #If the user inputs 1 then they can input another order if they didn't put in 1 then the program assumes that it is the end of a customers order
print "Your total is $", total * 1.13,"!"
total = total * 1.13
print
print "How much money was given?"
print
money = input ()* 1.0
while money < total:
print "Please input a valid number!"
money = input ()
print "The change should be $",money - total,"!"
This tortured me until I solved it. One rule I set for myself was NOT to use a case-by-case switch on modulo 5, but to use builtin functions. Nice puzzle. wim's "double it, round, then halve it" comment was close.
def nickelround(n):
N = int(n)
print "%0.2f" % (N + round((n - N) * 20) * 0.05)
In [42]:
x=0.57
int(x/0.05)*0.05
Out[42]:
0.55
Usually in these programming problems you're explicitly asked to solve for how to "make change", not just provide the total amount of change due (which is trivial). So you can just in-line the pennies correction into that function:
def make_change(bal):
bal = bal + .02 #correction for no pennies
currency = [20,10,5,1,.25,.1,.05]
change = {}
for unit in currency:
change[unit] = int(bal // unit)
bal %= unit
return change
This particular form returns a dict of change denominations and their corresponding counts.
As you already hinted, use the Decimal class (module decimal). Replace all floats in your code with decimal constructors like Decimal('13.52').
Now the function you want to use is 'quantize'.
You use it like that:
Decimal('1.63').quantize(Decimal('0.5'), rounding=ROUND_HALF_DOWN)
The parameter Decimal('0.5') indicates that you want to round to the halves.
UPDATE:
As the OP wanted to round to the units of 0.05, he must obviously use:
Decimal('1.63').quantize(Decimal('0.05'), rounding=ROUND_HALF_DOWN)
I'm going to be old-school and say, convert your number into a list of values with a null or some kind of tag to represent the decimal.
The make a variable to hold your rounded number and add each value from 1000s or whatever, to 100s, 10s and 1s. (You are looping of course).
Once your loop hits the tag, depending on how far you want to round, (this should be a parameter for your function) throw in a conditional to represent how you want to round ie. 5 means round up, 4 round down (this is another parameter). Then add the final value(s) and return your newly rounded number.
Step 2: Fire your teacher because this is an unbelievably easy problem.
Bare in mind, anyone who knows c or has worked with memory assignment should find this question a breeze.
You could use something as simple as this to round your numbers to a given base:
def round_func(x, base=0.05):
return round(base*round(float(x)/base), 2)
And since you want only 2 decimal places, you can just round it to 2 decimals. The inner round function is to round the given number as per the base, which is 0.05 in your case.
Do you know, how to use own functions?
Add this function to your code:
def nickelround(m):
return round(m/0.05,0)*0.05
and use it:
print "The change should be $", nickelround(money - total),"!"

Python function: Find Change from purchase amount [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I'm looking for the most efficient way to figure out a change amount (Quarters, dimes, nickels, and pennies) from a purchase amount. The purchase amount must be less than $1, and the change is from one dollar. I need to know how many quarters, dimes, nickels, and pennies someone would get back.
Would it be best to set up a dictionary?
Gee, you mean this isn't problem 2b in every programming course any more? Eh, probably not, they don't seem to teach people how to make change any more either. (Or maybe they do: is this a homework assignment?)
If you find someone over about 50 and have them make change for you, it works like this. Say you have a check for $3.52 and you hand the cashier a twnty. They'll make change by saying "three fifty-two" then
count back three pennies, saying "three, four, five" (3.55)
count back 2 nickels, (3.60, 3.65)
count back a dime (3.75)
a quarter (4 dollars)
a dollar bill (five dollars)
a $5 bill (ten dollars)
a $10 bill (twenty.)
That's at heart a recursive process: you count back the current denomination until the current amount plus the next denomination comes out even. Then move up to the next denomination.
You can, of course, do it iteratively, as above.
This is probably pretty fast - just a few operations per denomination:
def change(amount):
money = ()
for coin in [25,10,5,1]
num = amount/coin
money += (coin,) * num
amount -= coin * num
return money
Your best bet is to probably have a sorted dictionary of coin sizes, and then loop through them checking if your change is greater than the value, add that coin and subtract the value, otherwise move along to the next row in the dictionary.
Eg
Coins = [50, 25, 10, 5, 2, 1]
ChangeDue = 87
CoinsReturned = []
For I in coins:
While I >= ChangeDue:
CoinsReturned.add(I)
ChangeDue = ChangeDue - I
Forgive my lousy python syntax there. Hope that's enough to go on.
This problem could be solved pretty easy with integer partitions from number theory. I wrote a recursive function that takes a number and a list of partitions and returns the number of possible combinations that would make up the given number.
http://sandboxrichard.blogspot.com/2009/03/integer-partitions-and-wiki-smarts.html
It's not exactly what you want, but it could be easily modified to get your result.
The above soloution working.
amount=int(input("Please enter amount in pence"))
coins = [50, 25, 10, 5, 2, 1]
coinsReturned = []
for i in coins:
while amount >=i:
coinsReturned.append(i)
amount = amount - i
print(coinsReturned)
Alternatively a solution can reached by using the floor and mod functions.
amount = int(input( "Please enter amount in pence" ))
# math floor of 50
fifty = amount // 50
# mod of 50 and floor of 20
twenty = amount % 50 // 20
# mod of 50 and 20 and floor of 10
ten = amount % 50 % 20 // 10
# mod of 50 , 20 and 10 and floor of 5
five = amount % 50 % 20 % 10 // 5
# mod of 50 , 20 , 10 and 5 and floor of 2
two = amount % 50 % 20 % 10 % 5 // 2
# mod of 50 , 20 , 10 , 5 and 2 and floor of 1
one = amount % 50 % 20 % 10 % 5 % 2 //1
print("50p>>> " , fifty , " 20p>>> " , twenty , " 10p>>> " , ten , " 5p>>> " , five , " 2p>>> " , two , " 1p>>> " , one )
Or another solution
amount=int(input("Please enter the change to be given"))
endAmount=amount
coins=[50,25,10,5,2,1]
listOfCoins=["fifty" ,"twenty five", "ten", "five", "two" , "one"]
change = []
for coin in coins:
holdingAmount=amount
amount=amount//coin
change.append(amount)
amount=holdingAmount%coin
print("The minimum coinage to return from " ,endAmount, "p is as follows")
for i in range(len(coins)):
print("There's " , change[i] ,"....", listOfCoins[i] , "pence pieces in your change" )
I have an improve solution from above solutions
coins=[]
cost = float(input('Input the cost: '))
give = float(input('Tipe Amount given: '))
change = (give - cost)
change2 = change-int(change)
change2 = round(change2,2)*100
coin = [50,25,10,5,1]
for c in coin:
while change2>=c:
coins.append(c)
change2 = change2-c
half=coins.count(50)
qua = coins.count(25)
dime=coins.count(10)
ni=coins.count(5)
pen=coins.count(1)
dolars = int(change)
if half !=0 or qua != 0 or dime!=0 or ni!=0 or pen!=0:
print ('The change of', round(give,2), 'is:',change, 'like \n-dolas:',dolars,'\n-halfs:',half,'\n-quarters:',qua,'\n-dime:',dime,'\n-nickels:',ni,'\n-pennies:',pen)
else:
print ('The change from', round(give,2), 'is:',change,'and no coins')

Categories