[python] Range with step of type float

The documentation basically says that range must behave exactly as this implementation (for positive step):

def range(start, stop, step):
  x = start
  while True:
    if x >= stop: return
    yield x
    x += step

It also says that its arguments must be integers. Why is that? Isn't that definition also perfectly valid if step is a float?

In my case, I am esp. needing a range function which accepts a float type as its step argument. Is there any in Python or do I need to implement my own?


More specific: How would I translate this C code directly to Python in a nice way (i.e. not just doing it via a while-loop manually):

for(float x = 0; x < 10; x += 0.5f) { /* ... */ }

This question is related to python range

The answer is


Probably because you can't have part of an iterable. Also, floats are imprecise.


When you add floating point numbers together, there's often a little bit of error. Would a range(0.0, 2.2, 1.1) return [0.0, 1.1] or [0.0, 1.1, 2.199999999]? There's no way to be certain without rigorous analysis.

The code you posted is an OK work-around if you really need this. Just be aware of the possible shortcomings.


One explanation might be floating point rounding issues. For example, if you could call

range(0, 0.4, 0.1)

you might expect an output of

[0, 0.1, 0.2, 0.3]

but you in fact get something like

[0, 0.1, 0.2000000001, 0.3000000001]

due to rounding issues. And since range is often used to generate indices of some sort, it's integers only.

Still, if you want a range generator for floats, you can just roll your own.

def xfrange(start, stop, step):
    i = 0
    while start + i * step < stop:
        yield start + i * step
        i += 1

Here is a special case that might be good enough:

 [ (1.0/divStep)*x for x in range(start*divStep, stop*divStep)]

In your case this would be:

#for(float x = 0; x < 10; x += 0.5f) { /* ... */ } ==>
start = 0
stop  = 10
divstep = 1/.5 = 2 #This needs to be int, thats why I said 'special case'

and so:

>>> [ .5*x for x in range(0*2, 10*2)]
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]

This is what I would use:

numbers = [float(x)/10 for x in range(10)]

rather than:

numbers = [x*0.1 for x in range(10)]
that would return :
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

hope it helps.


The problem with floating point is that you may not get the same number of items as you expected, due to inaccuracy. This can be a real problem if you are playing with polynomials where the exact number of items is quite important.

What you really want is an arithmetic progression; the following code will work quite happily for int, float and complex ... and strings, and lists ...

def arithmetic_progression(start, step, length):
    for i in xrange(length):
        yield start + i * step

Note that this code stands a better chance of your last value being within a bull's roar of the expected value than any alternative which maintains a running total.

>>> 10000 * 0.0001, sum(0.0001 for i in xrange(10000))
(1.0, 0.9999999999999062)
>>> 10000 * (1/3.), sum(1/3. for i in xrange(10000))
(3333.333333333333, 3333.3333333337314)

Correction: here's a competetive running-total gadget:

def kahan_range(start, stop, step):
    assert step > 0.0
    total = start
    compo = 0.0
    while total < stop:
        yield total
        y = step - compo
        temp = total + y
        compo = (temp - total) - y
        total = temp

>>> list(kahan_range(0, 1, 0.0001))[-1]
0.9999
>>> list(kahan_range(0, 3333.3334, 1/3.))[-1]
3333.333333333333
>>>

In order to be able to use decimal numbers in a range expression a cool way for doing it is the following: [x * 0.1 for x in range(0, 10)]