Reputation: 333
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
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
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
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
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
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