[Tutor] range function and floats?

Wayne Werner waynejwerner at gmail.com
Wed Jan 5 16:02:00 CET 2011


On Wed, Jan 5, 2011 at 5:14 AM, Steven D'Aprano <steve at pearwood.info> wrote:

> Alan Gauld wrote:
>
>  ...this is more about learning how the range function and floats work than
>>> about writing a super-efficient program.
>>>
>>
>> Unfortunately they don't work together.
>>
>> range(0.1,0.5,0.1)  -> [0.1,0.2,0.3,0.4]  doesn't work
>> you need to do:
>>
>> for n in range(1,5):  use( n/10 )
>>
>
>
> There are pitfalls in writing a range() equivalent for floats. Here's one
> way that doesn't work:
>
>
> def new_range(start, end, step):
>    # DON'T USE THIS!!!
>    x = start
>    while x < end:
>        yield x
>        x += step
>
> Here it seems to work:
>
> >>> list(new_range(5, 10, 0.25))
> [5, 5.25, 5.5, 5.75, 6.0, 6.25, 6.5, 6.75, 7.0, 7.25, 7.5,
> 7.75, 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75]
>
> (Remember that the end argument is excluded!)
>
> But here it fails:
>
>
> >>> L = list(new_range(5, 10, 0.1))
> >>> L[-1] == 9.9  # expect the last value to be 9.9
> False
> >>> L[-1] == 10.0  # maybe it's 10 then
> False
>
> In fact, the last value is a totally unexpected 9.9999999999999822. Such is
> the perils of floating point rounding errors.
>
> I've written a recipe for a float range which I hope avoids as many of
> these problems as possible. It isn't possible to avoid *all* rounding error
> when doing floating point calculation, but this should minimize them:
>
> http://code.activestate.com/recipes/577068-floating-point-range/
>
> As a bonus, it allows you to choose whether the start and end points are
> included or excluded.


As an alternative to floating point, you can use the Decimal module:

import decimal

def new_range(start, stop, step):
    x = decimal.Decimal(str(start))
    step = decimal.Decimal(str(step))
    while x < stop:
        yield x
        x += step

x = list(new_range(5, 10, 0.1))
x[-1] == decimal.Decimal(str(9.9))
#True
float(x[-1]) == 9.9
#True

The decimal module allows you to get rid of those pesky floating point
errors. See http://docs.python.org/library/decimal.html for more info. On a
related note, if you're interested in working with rational numbers (1/23,
3/4, etc.) there is also a fraction module
http://docs.python.org/library/fractions.html.


HTH,
Wayne
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20110105/ea0d7bb5/attachment-0001.html>


More information about the Tutor mailing list