problem calculating minimum amount of coins in change using python - python

I have a homework assignment in which we have to write a program that outputs the change to be given by a vending machine using the lowest number of coins. E.g. £3.67 can be dispensed as 1x£2 + 1x£1 + 1x50p + 1x10p + 1x5p + 1x2p.
However, my program is outputting the wrong numbers. I know there will probably be rounding issues, but I think the current issue is to do with my method of coding this.
change=float(input("Input change"))
twocount=0
onecount=0
halfcount=0
pttwocount=0
ptonecount=0
while change!=0:
if change-2>-1:
change=change-2
twocount+=1
else:
if change-1>-1:
change=change-1
onecount+=1
else:
if change-0.5>-1:
change=change-0.5
halfcount+=1
else:
if change-0.2>-1:
change=change-0.2
pttwocount+=1
else:
if change-0.1>-1:
change=change-0.1
ptonecount+=1
else:
break
print(twocount,onecount,halfcount,pttwocount,ptonecount)
RESULTS:
Input: 2.3
Output: 11010
i.e. 3.2
Input: 3.2
Output:20010
i.e. 4.2
Input: 2
Output: 10001
i.e. 2.1

All your comparisons use >-1, so you give out change as long as you have more than -1 balance.
This would be correct if you were only dealing with integers, since there >-1 is equal to >=0.
For floating point numbers however, we have for example -0.5>-1, so we will give out change for negative balance (which we do not want).
So the correct way would be to replace all >-1 comparisons by >=0 (larger or equal to 0) comparisons.

The problem is how it calculates the change using your if/else statements. If you walk through the first example change-2>-1 will register true and then result will be .3 but on the next loop the if change - 1 > -1 you are expecting to be false but it's not it's actually -0.7. One of the best ways to do this would be with Python's floor // and mod % operators. You have to round some of the calculations because of the way Python handles floats
change=float(input("Input change"))
twocount=0
onecount=0
halfcount=0
pttwocount=0
ptonecount=0
twocount = int(change//2)
change = round(change%2,1)
if change//1 > 0:
onecount = int(change//1)
change = round(change%1,1)
if change//0.5 > 0:
halfcount = int(change//0.5)
change = round(change%0.5, 1)
if change//0.2 > 0:
pttwocount = int(change//0.2)
change = round(change%0.2, 1)
if change//0.1 > 0:
ptonecount = int(change//0.1)
change = round(change%0.1,1)
print(twocount,onecount,halfcount,pttwocount,ptonecount)
But given the inputs this produces
Input: 2.3
Output: 1 0 0 1 1
Input: 3.2
Output:1 1 0 1 0
Input: 2
Output: 1 0 0 0 0

Related

My Function To Count The Largest Binary Gap Doesn't Work But I Can't Figure Out Why

I'm working through the Codility problems and I have gotten the first one almost correct. The task is to write a function which returns the longest binary gap (a sequence of 0s in between 1s) in a binary number. I have gotten all of the test numbers correct apart from 9, which should be 2 (its binary representation is 1001) but which my function returns as 0. I can't seem to figure out why.
My function is as follows:
def Solution(N):
x = bin(N)[2:]
x_string = str(x)
y = (len(x_string))
count = 0
max = 0
for index, item in enumerate(x_string):
if item == "1":
count = 0
elif item == "0" and x_string[index + 1:y-1] != "0"*(y -1 - (index + 1)):
count = count + 1
if count > max:
max = count
print(max)
The complicated indexing and second condition in the elif statement is so that when a 0 is not contained between two 1s then it isn't recognised as the beginning of a binary gap e.g. when the for loop looks at the second character in bin(16) = 10000, it doesn't set count to 1 because all of the remaining characters in the string are also zero.
Simple solution
x_string[index + 1:y-1] != "0"
this bit wants to take a look at the whole string that's left, but the end argument isn't inclusive,it's exluded, so if string length = 4; string[0:4] is the whole string.
source: https://docs.python.org/3/tutorial/introduction.html
-Sam

Count the dice throws to get to file 5 100 times(board is 0-5)

I'm trying to find out how many times you have to throw the dice to get on file 5 100 times(board is played from 0 to 5). This is how I tried(I know the answer is 690 but I don't know what I'm doing wrong).
from random import *
seed(8)
five = 0
count = 0
add = 0
while five < 100:
count = count + 1
print(randint(1,6))
add = add + randint(1,6)
if add % 5 == 0 :
five = five + 1
else: add = add + randint(1,6)
print(count)
This is the code I think you were trying to write. This does average about 600. Is it possible your "answer" came from Python 2? The random seed algorithm is quite likely different.
from random import *
seed(8)
five = 0
count = 0
add = 0
while five < 100:
count += 1
r = randint(0,5)
if r == 5:
five += 1
else:
add += r
print(count, add)
You're adding a second dice throw every time you don't get on 5, this makes the probability distribution irregular (i.e. advancing by 7 will be more probable (1/6) than any other value, e.g. 1/9 for 5) so your result will not be the same as counting single throws.
BTW there is no fixed result for this, just a higher probability around a given number of throws. However, given that you seeded the random number generator with a constant, every run should give the same result. And it should be the right one if you don't double throw the dice.
Here is an example of the process that arrives at 690:
import random
random.seed(8)
fiveCount = 0
throwCount = 0
position = 0
while fiveCount < 100:
position = (position + random.randint(1,6)) % 6
throwCount += 1
fiveCount += position == 5
print(throwCount) # 690
Other observations:
Updating the position wraps around using modulo 6 (there are 6 positions from 0 to 5 inclusively)
Your check of add%5 == 0 does not reflect this. It should have been add%6 == 5 instead but it is always preferable to model the computation as close as possible to the real world process (so keep the position in the 0...5 range)

Convert float number into binary

import struct
def print_binary(number_string):
bin = ""
if "." in number_string:
number_string = float(number_string)
bin += bin(struct.unpack('!i',struct.pack('!f', number_string)))
else:
num = int(number_string)
bin += "{0:b}".format(num)
print(bin)
I'm having trouble with converting a number with a decimal in it to binary (my if statement)
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
I get an error when it gets up to 12.4
I used recursion. But there can be a recursion limit on some value here.
Here is the method I used by hand.
Fractional Part = .6875 in base 10
.6875*2 equals 1.375 whole number is 1
.375*2 equals 0.75 whole number is 0
.75*2 equals 1.5 whole number is 1
.5*2 equals 1.0 whole number is 1
Hence .6875D = .1011 in base 2
However, think about the value 12.4. It will go forever!
.4*2 = .8
.8*2 = 1.6
.6*2 = .2
.2*2 = .4
... and so on
So we have to set a limit in our recursion calculation. I made it 10. Although this does not sound like a lot, see how accurate it is.
My input of 12.4 returns 1100.0110011001 which is equal to 12.3994140625
Pretty close, feel free to play with that number, take the ceiling of it, etc.
Here is the code:
def get_integer_part(pre_decimal_string):
# special case of negative 0 being a prefix "-0.6"
if pre_decimal_string == "-0":
return "-0"
else:
num = int(pre_decimal_string)
return "{0:b}".format(num)
def get_decimal_part(post_decimal_string, string_builder, recurse):
recurse += 1
post_decimal_value = float("." + post_decimal_string)
if post_decimal_value == 0 or recurse > 10:
return string_builder
else:
temp_mult_str = str(post_decimal_value * 2)
temp_mult_split = temp_mult_str.split(".")
string_builder += temp_mult_split[0]
return get_decimal_part(temp_mult_split[1], string_builder, recurse)
def print_binary(number_string):
# handle case of no preceding 0 ".3" or
if number_string[0] == ".":
number_string = "0" + number_string
# handle case of no preceding 0 and is negative
if number_string[0:2] == "-.":
number_string = "-0" + number_string[1:]
if "." in number_string:
str_split = number_string.split(".")
print(get_integer_part(str_split[0]) + "." + str(get_decimal_part(str_split[1], "", 0)))
else:
print(get_integer_part(number_string))
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
print(test_values)
for each in test_values:
print_binary(each)
# special cases
print_binary("-.7")
print_binary(".67")
Here is the final output:
0
10011010010
-10011010010
1100.0110011001
0.1001100110
-1100.0110011001
-0.1001100110
-1001001100101100000001011010010.0001111110
-0.1011001100
0.1010101110
Although I would have done this differently, I kept your code and format as much as possible to make it easiest for you to learn.

How can I average multiple outputs independently in python

PYTHON 3: Hi, so I have this piece of code
for money in range(0, 2501, 500):
print("{} Euro".format(money), end='')
throws = 0
d = trump.possession(board)
while False in d.values():
prevLoc = piece.location
piece.move(trump.throw())
throws += 1
if piece.location < prevLoc:
money += 200
if board.names[piece.location] in d and d[board.names[piece.location]] == False and money >= board.values[piece.location]:
money -= board.values[piece.location]
d[board.names[piece.location]] = True
return throws
and this code takes 0 money to start with, runs the code, looks for amount of throws required to buy the entire board, does the same with 500 starting money, 1000 and so forth
my question is, how can i take the average of the throws to buy the entire board for each starting value? the way my code is now it returns the amount of throws for all the starting values, but simulated once, so it may not be accurate.
I searched a lot, and tried some things but i had problems with this one because I want to like run it, say for example, 2000 times, and get the average for each starting value for the money.
anyone got any tips for this? been struggling on it for a while..
i tried making a for loop from 0 to 2000 and then inside of that another for loop that prints 0-2500 and then uses the code below in a function, appends the return value of throws into a list and sums it up and devides it by 2000, it did not turn out so good...
I'm going to assume this is in a function, due to the return statement. You need to collect outputs into a list and then average that at the end.
def calc_throws(simulations):
throw_list = []
average = lambda x: sum(x)/len(x)
for i, money in enumerate(range(0, 2501, 500)):
print("{} Euro".format(money), end='')
throw_list.append([money, []])
for _ in range(simulations):
throws = 0
d = trump.possession(board)
while False in d.values():
prevLoc = piece.location
piece.move(trump.throw())
throws += 1
if piece.location < prevLoc:
money += 200
if board.names[piece.location] in d and d[board.names[piece.location]] == False and money >= board.values[piece.location]:
money -= board.values[piece.location]
d[board.names[piece.location]] = True
throw_list[i][1].append(throws)
throw_list[i][1] = average(throw_list[i][1])
return throw_list
Rather than a single number, this returns a list of lists like #[[0,20],[500,15],...[2500,3]] (or whatever reasonable numbers are) which gives you the average for each amount of starting money.

Python If Function for Ranged Field

Actually this is a Python in GIS, so I use table in my Arcgis and try to count the field and divided it by using category.
I have Field named Elevation
the data contain integer example :
1 - 2
3 - 6
2 - 3
8.5 - 12
11 - 12
I need to categorize it using rule that if
Elevation < 1 then Index = 0.3 ,if Elevation = 2 - 3 Index = 0.6, if Elevation > 3 Index = 1
I have this code :
def Reclass( Elevation ):
r_min, r_max = (float(s.strip()) for s in Elevation.split('-'))
print "r_min: {0}, r_max: {1}".format(r_min,r_max)
if r_min < 1 and r_max < 1:
return 0.333
elif r_min >= 1 and r_max >= 1 and r_min <= 3 and r_max <= 3:
return 0.666
elif r_min > 3 and r_max > 3:
return 1
elif r_min <= 3 and r_max > 3:
return 1
else:
return 999
my question is how to strip it, and categorized it using my rule above?
Thanks before
Based on comments, your field is a string that contains ranges of the form you describe above.
Firstly, this is horrible database design. The minimum and maximum should be separate columns of integer types. shakes fist at ESRI more for discouraging good database design
Furthermore, your rule is insufficient for dealing with a range. A range check would either need to compare against either 1 end of the range or both ends. So you will have to clarify exactly what you want for your "indexing" rule.
Given that you have strings representing ranges, your only option is to parse the range into its minimum and maximum and work with those. That's not too hard in Python:
>>> r = "3 - 6"
>>> r_min, r_max = (int(s.strip()) for s in r.split('-'))
>>> r_min
3
>>> r_max
6
What does this do?
It's pretty simple, actually. It splits the string by the -. Then it loops over the resulting list, and each element has its leading and trailing whitespace removed and is then converted into an int. Finally, Python unpacks the generator on the right to fill in the variables on the left.
Be aware that malformed data will cause errors.
Once you've clarified your "index" rule, you can figure out how to use this minimum and maximum to get your "index".
I have borrowed code from you and #jpmc26 below. This code (minus the print statements that are just there for testing) should work for you in the Field Calculator of ArcMap but it is simply Python code. The problem is that you have not told us what you want to do when the two ends of a range fall into different categories so for now I have used an else statement to put out 999.
def Reclass( Elevation ):
r_min, r_max = (float(s.strip()) for s in Elevation.split('-'))
print "r_min: {0}, r_max: {1}".format(r_min,r_max)
if r_min < 1 and r_max < 1:
return 0.333
elif r_min >= 1 and r_max >= 1 and r_min <= 3 and r_max <= 3:
return 0.666
elif r_min > 3 and r_max > 3:
return 1
else:
return 999
print Reclass("0 - 1.1")
print Reclass("5.2 - 10")
print Reclass("2 - 3")
print Reclass("0 - 0")

Categories

Resources