python 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 version 2.7

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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.

Method 2

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.

Method 3

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

Method 4

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)

Method 5

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]


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x