Home > other >  python not recognising 0.1 // 0.1 = 1, 0.2 // 0.2 = 1, etc. when div'ing float by multiple floa
python not recognising 0.1 // 0.1 = 1, 0.2 // 0.2 = 1, etc. when div'ing float by multiple floa

Time:01-23

I am in the process of creating a program to determine the change of a user, which first takes in how much they owe and then how much they pay. The program ensures they do not give anything other than numbers and decimal points, and that the amount they pay is equal to or greater than how much they owe.

Then the program begins a series of if statements to DIV the change by (most) £ increments, and if the result is greater than 0, it will MOD the current change by the increment being assessed. e.g. if my change is 20, then my change DIV 20 = 1 and will return acknowledgement to the user, MOD change by 20 too, and the result is the remaining change, which will be checked by the rest of the if statements.

allowedchars = set("1234567890.")
Checkpay = True
Checkrec = True
while Checkpay == True:
 Amountpay = input("What amount must be paid? ")
 if set(Amountpay).issubset(allowedchars):
    Checkpay = False
    Amountpay = float(Amountpay)
    print(format(Amountpay, ".2f"))
 else:    
    print("Invalid amount, please try again.")

#evaluate received amount > amount to pay and if amount received is valid input, both at once:
while Checkrec == True:
 Amountrec = input("What amount have I received? ")
 if set(Amountrec).issubset(allowedchars) and float(Amountrec) >= Amountpay:
    Checkrec = False
    Amountrec = float(Amountrec)
    print(format(Amountrec, ".2f"))
 else:
    print("Invalid amount/not enough money received, please try again: ")
    
change = Amountrec - Amountpay
change = format(change, ".2f")
print("Your change is: £", change)
twenty = int(float(change) // 20)
if twenty > 0:
    print("You will receive "   str(twenty)   " £20 banknote(s).")
    change = float(change) % 20
    print(format(change, ".2f"))
ten = int(float(change) // 10)
if ten > 0:
    print("You will receive 1 £10 banknote.")
    change = float(change) % 10
    print(format(change, ".2f"))
five = int(float(change) // 5)
if five > 0:
    print("You will receive 1 £5 banknote.")
    change = float(change) % 5
    print(format(change, ".2f"))
two = int(float(change) // 2)
if two > 0:
    print("You will receive "   str(two)   " £2 coin(s).")
    change = float(change) % 2
    print(format(change, ".2f"))
one = int(float(change) // 1)
if one > 0:
    print("You will receive "   str(one)   " £1 coin.")
    change = float(change) % 1
    print(format(change, ".2f"))
fifp = int(float(change) // 0.5)
if fifp > 0:
    print("You will receive "   str(fifp)   " 50p coin.")
    change = float(change) % 0.5
    print(format(change, ".2f"))
twenp = int(float(change) // 0.2)
if twenp > 0:
    print("You will receive "   str(twenp)   " 20p coin(s).")
    change = float(change) % 0.2
    print(format(change, ".2f"))
tenp = int(float(change) // 0.10)
print(tenp)
if tenp > 0:
    print("You will receive "   str(tenp)   " 10p coin.")
    change = float(change) % 0.10
    print(format(change, ".2f"))
fivep = int(float(change) // 0.05)
if fivep > 0:
    print("You will receive "   str(fivep)   " 5p coin.")
    change = float(change) % 0.05
    print(format(change, ".2f"))

Everything's fine when I check integer change against integer increment. But when I check, say, 0.70 change against the ifs, I get this:

What amount must be paid? 0.1
0.10
What amount have I received? 0.8
0.80
Your change is: £ 0.70
You will receive 1 50p coin.
0.20
1
You will receive 1 10p coin.
0.10
You will receive 1 5p coin.
0.05

instead of 50p and 20p, or if I check 0.15 change:

What amount must be paid? 0.05
0.05
What amount have I received? 0.2
0.20
Your change is: £ 0.15
1
You will receive 1 10p coin.
0.05

As if I don't need 5p change as well.

Checking just 1 pence increment (e.g. 0.50 change calculated) works fine. Sometimes, even non-consecutive increments (e.g. 0.60 change calculated, which gives out 50p and 5p instead of 50p and 10p) will be incorrectly checked.

What's going on with my code, or with python (version 3.8.6)? How can I get this code to output the right amount and statements when it comes to pence?

CodePudding user response:

You might be able to solve this by making a new float class

class AccurateFloat(int):
    def __new__(cls, x):
        # some inaccuracies could occur at the first conversion
        return super(AccurateFloat, cls).__new__(cls, x * 10**6) # the 6 can be 'any' large number

    def get_float(self):
        return self / 10 ** 6 # some inaccuracies could occur at the second conversion 

CodePudding user response:

You can simplify this by making it "table-driven". Also, you can eliminate all the floating point issues by converting the value to pence and then work solely with integers. Here's an example:

CHANGE = [(5000, 'Fifty pound note'), (2000, 'Twenty pound note'), (1000, 'Ten pound note'), (500, 'Five pound note'), (100, 'One pound coin'),
          (50, '50p coin'), (20, '20p coin'), (10, '10p coin'), (5, '5p coin'), (2, '2p coin'), (1, '1p coin')]


def calc(c):
    c = int(c * 100)
    for change in CHANGE:
        if c >= change[0]:
            v = c // change[0]
            print(f'{v} {change[1]}{"s" if v > 1 else ""}')
            c -= v * change[0]


calc(106.76)

Output:

2 Fifty pound notes
1 Five pound note
1 One pound coin
1 50p coin
1 20p coin
1 5p coin
1 1p coin
  •  Tags:  
  • Related