On Fri, Mar 1, 2013 at 12:33 PM, Henry Gomersall <heng@cantab.net> wrote:
On Fri, 2013-03-01 at 13:25 +0100, Sebastian Berg wrote:
there has been a request on the issue tracker for a step parameter to linspace. This is of course tricky with the imprecision of floating point numbers.
How is that different to arange? Either you specify the number of points with linspace, or you specify the step with arange. Is there a third option?
arange is designed for ints and gives you a half-open interval, linspace is designed for floats and gives you a closed interval. This means that when arange is used on floats, it does weird things that linspace doesn't: In [11]: eps = np.finfo(float).eps In [12]: np.arange(0, 1, step=0.2) Out[12]: array([ 0. , 0.2, 0.4, 0.6, 0.8]) In [13]: np.arange(0, 1 + eps, step=0.2) Out[13]: array([ 0. , 0.2, 0.4, 0.6, 0.8, 1. ]) In [14]: np.linspace(0, 1, 6) Out[14]: array([ 0. , 0.2, 0.4, 0.6, 0.8, 1. ]) In [15]: np.linspace(0, 1 + eps, 6) Out[15]: array([ 0. , 0.2, 0.4, 0.6, 0.8, 1. ]) The half-open/closed thing also has effects on what kind of api is reasonable. arange(0, 1, step=0.8) makes perfect sense (it acts like python range(0, 10, step=8)). linspace(0, 1, step=0.8) is just incoherent, though, because linspace guarantees that both the start and end points are included.
My usual hack to deal with the numerical bounds issue is to add/subtract half the step.
Right. Which is exactly the sort of annoying, content-free code that a library is supposed to handle for you, so you can save mental energy for more important things :-). The problem is to figure out exactly how strict we should be. Like, presumably linspace(0, 1, step=0.8) should fail, rather than round 0.8 to 0.5 or 1. That would clearly violate "in the face of ambiguity, refuse the temptation to guess". OTOH, as Sebastian points out, requiring that the step be *exactly* a divisor of the value (stop - start), within 1 ULP, is probably obnoxious. Would anything bad happen if we just required that, say, (stop - start)/step had to be within "np.allclose" of an integer, i.e., to some reasonable relative and absolute precision, and then rounded the number of steps to match that integer exactly? -n