4
$\begingroup$

I am trying to rewrite some MATLAB/Octave code in Python, and I don't know what would be the nicest or most intuitive way of writing

octave:10> dt = 0.1;
octave:12> T = 0:dt:1
T =

    0.00000    0.10000    0.20000    0.30000    0.40000    0.50000    0.60000    0.70000    0.80000    0.90000    1.00000
octave:15> dt = 0.17;
octave:16> T = 0:dt:1
T =

    0.00000    0.17000    0.34000    0.51000    0.68000    0.85000

which creates a discretization of the interval [0, 1] with step 0.1, as it's seen. I referred to the NumPy/MATLAB mathesaurus and it uses arange function, but it's not suitable for non-integer values as it's stated in the documentation and shown in this SO question. On the other hand, playing with linspace is not appealing to me because it takes care of endpoints, not spacing.

Which would be a straight-forward, one-line way of doing this in Python?

$\endgroup$
4
$\begingroup$

MATLAB and Octave are susceptible to the same subtle floating-point issues that Python is, where you can get a slightly unexpected result if you do not anticipate rounding issues. On the other hand, this is quite convenient syntax to have! You can easily "bake" a simple function to do this from the existing functionality in numpy.linspace, which is a very Pythonic way to do things!

# use Python3 syntax in Python2 to get clean, consistent integer division  
from __future__ import division   
import numpy as np

def lrange(r1, inc, r2):
    """Provide spacing as an input and receive samples back by wrapping `numpy.linspace`"""
    n = ((r2-r1)+2*np.spacing(r2-r1))//inc
    return np.linspace(r1,r1+inc*n,n+1)

> lrange(0,0.1,1)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ])

> lrange(0,0.17,1)
array([ 0.  ,  0.17,  0.34,  0.51,  0.68,  0.85])

Edit: I've added a floating point epsilon to the computation that will handle small floating-point errors in the operands/representation per Juanlu001's comment.

$\endgroup$
  • $\begingroup$ Ah, didn't know about the existence of the integer division operator! In fact you do not need the __future__ import statement. Thank you! $\endgroup$ – astrojuanlu May 25 '12 at 17:41
  • $\begingroup$ You're absolutely right, an earlier version of the function used "true division". I'm going to leave the import statement in there because it's a reasonably important piece of the language to know about, even if it's not used here. There are more details on division in Python in PEP 238. $\endgroup$ – Aron Ahmadia May 26 '12 at 7:26
  • $\begingroup$ Well, after some days I went back to this and discovered that lrange(0, 0.1, 1) is actually [0., ..., 0.8, 0.9]. This is because 0.1 is actually 0.100000000000000006. Here and there is mentioned that there are roundoff errors and the like, but then I don't know how it is implemented in MATLAB / Octave. $\endgroup$ – astrojuanlu Jun 8 '12 at 11:46
  • $\begingroup$ --I mean, at least in my computer. $\endgroup$ – astrojuanlu Jun 8 '12 at 12:04
  • $\begingroup$ @Juanlu001 - That's annoying, I think the only fix would be to do something like: ((r2-r1)+np.spacing(r2-r1))//inc $\endgroup$ – Aron Ahmadia Jun 8 '12 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.