This happens because Python (like most modern programming languages) uses floating point arithmetic, which cannot exactly represent some numbers (see Is floating point math broken?).
This means that, regardless of whether you're using Python 2, Python 3, R, C, Java, etc. you have to think about the effects of adding two floating point numbers together.
np.arange
works by repeatedly adding the step
value to the start
value, and this leads to imprecision in the end:
>>> start = -1
>>> for i in range(1000):
... start += 0.001
>>> start
8.81239525796218e-16
Similarly:
>>> x = np.arange(-1., 0.001, 0.01)
>>> x[-1]
8.8817841970012523e-16
The typical pattern used to circumvent this is to work with integers whenever possible if repeated operations are needed. So, for example, I would do something like this:
>>> x = 0.01 * np.arange(-100, 0.1)
>>> x[-1]
0.0
Alternatively, you could create a one-line convenience function that will do this for you:
>>> def safe_arange(start, stop, step):
... return step * np.arange(start / step, stop / step)
>>> x = safe_arange(-1, 0.001, 0.01)
>>> x[-1]
0
But note that even this can't get around the limits of floating point precision; for example, the number -0.99 cannot be represented exactly in floating point:
>>> val = -0.99
>>> print('{0:.20f}'.format(val))
-0.98999999999999999112
So you must always keep that in mind when working with floating point numbers, in any language.