3
votes

I must translate some Matlab code into Python 3 and I often come across ranges of the form start:step:stop. When these arguments are all integers, I easily translate this command with np.arange(), but when some of the arguments are floats, especially the step parameter, I don't get the same output in Python. For example,

7:8 %In Matlab
7 8

If I want to translate it in Python I simply use :

np.arange(7,8+1)
array([7, 8])

But if I have, let's say :

7:0.3:8 %In Matlab
7.0000    7.3000    7.6000    7.9000

I can't translate it using the same logic :

np.arange(7, 8+0.3, 0.3)
array([ 7. ,  7.3,  7.6,  7.9,  8.2])

In this case, I must not add the step to the stop argument.

But then, if I have :

7:0.2:8 %In Matlab
7.0000    7.2000    7.4000    7.6000    7.8000    8.0000

I can use my first idea :

np.arange(7,8+0.2,0.2)
array([ 7. ,  7.2,  7.4,  7.6,  7.8,  8. ])

My problem comes from the fact that I am not translating hardcoded lines like these. In fact, each parameters of these ranges can change depending on the inputs of the function I am working on. Thus, I can sometimes have 0.2 or 0.3 as the step parameter. So basically, do you guys know if there is another numpy/scipy or whatever function that really acts like Matlab range, or if I must add a little bit of code by myself to make sure that my Python range ends up at the same number as Matlab's?

Thanks!

2
if you are working with floats it might be preferable to use numpy.linspace to which you pass the final array size more than a step. It avoids some rounding nuisances.Learning is a mess

2 Answers

7
votes

You don't actually need to add your entire step size to the max limit of np.arange but just a very tiny number to make sure that that max is enclose. For example the machine epsilon:

eps = np.finfo(np.float32).eps

adding eps will give you the same result as MATLAB does in all three of your scenarios:

In [13]: np.arange(7, 8+eps)
Out[13]: array([ 7.,  8.])

In [14]: np.arange(7, 8+eps, 0.3)
Out[14]: array([ 7. ,  7.3,  7.6,  7.9])

In [15]: np.arange(7, 8+eps, 0.2)
Out[15]: array([ 7. ,  7.2,  7.4,  7.6,  7.8,  8. ])
1
votes

Matlab docs for linspace say

linspace is similar to the colon operator, ":", but gives direct control over the number of points and always includes the endpoints. "lin" in the name "linspace" refers to generating linearly spaced values as opposed to the sibling function logspace, which generates logarithmically spaced values.

numpy arange has a similar advise.

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.

End of interval. The interval does not include this value, except in some cases where step is not an integer and floating point round-off affects the length of out.

So differences in how step size gets translated into number of steps can produces differences in the number of steps. If you need consistency between the two codes, linspace is the better choice (in both).