[Tutor] while loop ends prematurly

Dave Angel d at davea.name
Mon Jan 2 04:25:57 CET 2012


On 01/01/2012 09:48 PM, brian arb wrote:
> Hello,
> Can some please explain this to me?
> My while loop should continue while "owed" is greater than or equal to "d"
>
> first time the function is called
> the loop exits as expected
> False: 0.000000>= 0.010000
> the next time it does not
> False: 0.010000>= 0.010000
>
> Below is the snippet of code, and the out put.
>
> Thanks!
>
> def make_change(arg):
>    denom = [100.0, 50.0, 20.0, 10.0, 5.0, 1.0, 0.25, 0.10, 0.05, 0.01]
>    owed = float(arg)
>    payed = []
>    for d in denom:
>      while owed>= d:
>        owed -= d
>        b = owed>= d
>        print '%s: %f>= %f' % (b, owed, d)
>        payed.append(d)
>    print sum(payed), payed
>    return sum(payed)
>
> if __name__ == '__main__':
>    values = [21.48, 487.69] #, 974.41, 920.87, 377.93, 885.12, 263.47,
> 630.91, 433.23, 800.58]
>    for i in values:
>      make_change(i))
>
>
> False: 1.480000>= 20.000000
> False: 0.480000>= 1.000000
> False: 0.230000>= 0.250000
> True: 0.130000>= 0.100000
> False: 0.030000>= 0.100000
> True: 0.020000>= 0.010000
> True: 0.010000>= 0.010000
> False: 0.000000>= 0.010000
> 21.48 [20.0, 1.0, 0.25, 0.1, 0.1, 0.01, 0.01, 0.01]
> True: 387.690000>= 100.000000
> True: 287.690000>= 100.000000
> True: 187.690000>= 100.000000
> False: 87.690000>= 100.000000
> False: 37.690000>= 50.000000
> False: 17.690000>= 20.000000
> False: 7.690000>= 10.000000
> False: 2.690000>= 5.000000
> True: 1.690000>= 1.000000
> False: 0.690000>= 1.000000
> True: 0.440000>= 0.250000
> False: 0.190000>= 0.250000
> False: 0.090000>= 0.100000
> False: 0.040000>= 0.050000
> True: 0.030000>= 0.010000
> True: 0.020000>= 0.010000
> False: 0.010000>= 0.010000
> 487.68 [100.0, 100.0, 100.0, 100.0, 50.0, 20.0, 10.0, 5.0, 1.0, 1.0, 0.25,
> 0.25, 0.1, 0.05, 0.01, 0.01, 0.01]
>
You're using float values and pretending that they can accurately 
represent dollars and cents. 0.19 (for example) cannot be exactly 
represented in a float, and when you start adding up multiple of these, 
sooner or later the error will become visible.  This is a problem with 
binary floating point, and I first encountered it in 1967, when the 
textbook for Fortran made an important point about never comparing 
floating point values for equals, as small invisible errors are bound to 
bite you.

Easiest answer is to use integers.  Scale everything up by a factor of 
100, and you won't need floats at all.  Just convert when printing (and 
even then you may get into trouble).

Another answer is to use Decimal class, which CAN represent decimal 
values exactly.

BTW, if this is supposed to represent US legal tender, you left out the 
fifty-cent piece as well as the two dollar bill.

-- 

DaveA



More information about the Tutor mailing list