smashtastic
smashtastic

Reputation: 333

numpy arange unexpected results

I am using the arange function to define my for loop iterations and getting unexpected results.

i = arange(7.8, 8.4, 0.05)
print i

yeilds the following:

[ 7.8   7.85  7.9   7.95  8.    8.05  8.1   8.15  8.2   8.25  8.3   8.35 8.4 ]

yet using the stop value of 8.35 as follows

i = arange(7.8, 8.35, 0.05)

yields the following

[ 7.8   7.85  7.9   7.95  8.    8.05  8.1   8.15  8.2   8.25  8.3 ]

But I want my range to end at 8.35! I know I can use the stop value of > 8.35 and < 8.4 to achieve my result, but why is it different and in my mind, inconsistent?

Edit: I am using Python 2.7

Upvotes: 21

Views: 15934

Answers (5)

Falcon77
Falcon77

Reputation: 53

Add a bit of a corrector float to the endpoint:

import numpy as np

step = 0.05
corr = 0.01 if step == 0.05 else 0.0

i = np.arange(7.8,8.35+corr,step)
print(i)

OUTPUT:

$ python a.py [7.8 7.85 7.9 7.95 8. 8.05 8.1 8.15 8.2 8.25 8.3 8.35]

Upvotes: 1

ClaGor
ClaGor

Reputation: 21

I had the same problem and I implemented my own function to correct for this rounding issue with numpy.arange :

import numpy as np
def my_arange(a, b, dr, decimals=6):
    res = [a]
    k = 1
    while res[-1] < b:
        tmp = round(a + k*dr,decimals)
        if tmp > b:
            break   
        res.append(tmp)
        k+=1

    return np.asarray(res)

Upvotes: 2

avasal
avasal

Reputation: 14874

the help of arange function says

    For floating point arguments, the length of the result is
    ``ceil((stop - start)/step)``.  Because of floating point overflow,
    this rule may result in the last element of `out` being greater
    than `stop`.

for python 2.7, Conversions between floating-point numbers and strings are now correctly rounded on most platforms.

in 2.7

>>> float(repr(2.3))
2.3

in 2.6

>>> float(repr(2.3))
2.2999999999999998

Upvotes: 5

Brendan Wood
Brendan Wood

Reputation: 6450

Perhaps it has to do with limitations on floating point numbers. Due to machine precision, it is not possible to store every conceivable value perfectly as a floating point. For example:

>>> 8.4
8.4000000000000004
>>> 8.35
8.3499999999999996

So, 8.4 as a floating point is slightly greater than the actual value of 8.4, while 8.35 as a floating point is a tiny bit less.

Upvotes: 14

Joe Kington
Joe Kington

Reputation: 284870

I'm guessing that you're seeing the effects of floating point rounding.

numpy.arange does the same thing as python's range: It doesn't include the "endpoint". (e.g. range(0, 4, 2) will yield [0,2] instead of [0,2,4])

However, for floating point steps, the rounding errors are accumulate, and occasionally the last value will actually include the endpoint.

As noted in the documentation for arange:

When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use linspace for these cases.

numpy.linspace generates a specified number of points between a starting and ending point. Incidentally, it does include the endpoints by default.

Upvotes: 26

Related Questions