Your intuition seems to be that if endpoint=False is specified, then the last element of the returned array should be 1 less than the stop value.
Suppose we implement things that way. What does the following linspace call return?
numpy.linspace(0, 0.5, 5, endpoint=False)
Is it going to end at -0.5, counting down? That wouldn't make much sense.
numpy.linspace always divides the interval from start to stop into equally-sized chunks, and it always returns an array of length num. The difference between endpoint=True and endpoint=False is that with endpoint=False, it makes one extra chunk to compensate for leaving out the right endpoint. The step from 16 to 18 is the same size as the step from 18 to the omitted 20.
Your intuition seems to be that if endpoint=False is specified, then the last element of the returned array should be 1 less than the stop value.
Suppose we implement things that way. What does the following linspace call return?
numpy.linspace(0, 0.5, 5, endpoint=False)
Is it going to end at -0.5, counting down? That wouldn't make much sense.
numpy.linspace always divides the interval from start to stop into equally-sized chunks, and it always returns an array of length num. The difference between endpoint=True and endpoint=False is that with endpoint=False, it makes one extra chunk to compensate for leaving out the right endpoint. The step from 16 to 18 is the same size as the step from 18 to the omitted 20.
It would be helpful to look at the source here. This will allow you to walk through what the function is doing, which will give you a better understanding of the output of linspace.
Two parameters are used to calculate the step size: div and delta. However, the difference between endpoint=True, and endpoint=False, is that div is equal to num-1 if endpoint=True, and num if endpoint=False.
div = (num - 1) if endpoint else num
Here are the other relevent pieces of the source (very slimmed down):
delta = stop - start
y = _nx.arange(0, num, dtype=dt)
# ...
if num > 1:
step = delta / div
# ...
y = y * step
# ...
y += start
If we walk through each of these the outputs make a lot more sense.
endpoint=True:
div = num - 1 # 4
y = _nx.arange(0, num, dtype=dt) # [0, 1, 2, 3, 4]
delta = 20 - 10 # 10
step = delta / div # 2.5
y = y * step # [0.0, 2.5, 5.0, 7.5, 10.0]
y += start # [10.0, 12.5, 15.0, 17.5, 20.0]
endpoint=False:
div = num # 5
y = _nx.arange(0, num, dtype=dt) # [0, 1, 2, 3, 4]
delta = 20 - 10 # 10
step = delta / div # 2
y = y * step # [0.0, 2.0, 4.0, 6.0, 8.0]
y += start # [10.0, 12.0, 14.0, 16., 18.0]
The shortest and most elegant way (from my perspective) is:
import numpy as np
start = 0
step = 1.25
num = 9
result = start + np.arange(0, num) * step
returns
[ 0. 1.25 2.5 3.75 5. 6.25 7.5 8.75 10. ]
A deleted answer pointed out that linspace takes an endpoint parameter.
With that, 2 examples given in other answers can be written as:
In [955]: np.linspace(0, 0+(0.1*3),3,endpoint=False)
Out[955]: array([ 0. , 0.1, 0.2])
In [956]: np.linspace(0, 0+(5*3),3,endpoint=False)
Out[956]: array([ 0., 5., 10.])
In [957]: np.linspace(0, 0+(1.25*9),9,endpoint=False)
Out[957]: array([ 0. , 1.25, 2.5 , 3.75, 5. , 6.25, 7.5 , 8.75, 10. ])
Look at the functions defined in numpy.lib.index_tricks for other ideas on how to generate ranges and/or grids. For example, np.ogrid[0:10:9j] behaves like linspace.
def altspace(start, step, count, endpoint=False, **kwargs):
stop = start+(step*count)
return np.linspace(start, stop, count, endpoint=endpoint, **kwargs)