[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