Hmm… you are right. The requirement is indeed to hit zero and the extremes if we look a the MATLAB code.
MATLAB’s colon syntax doesn’t exactly hit its endpoints.
If I remember right, it can sometimes generate a final value that’s greater than your max
.
Maybe this? (edited again, I am searching for the most simple workaround, not a general solution, sorry):
julia> srange(dx,xmax) = -(xmax-xmax%dx+dx):dx:(xmax-xmax%dx+dx);
julia> collect(srange(0.0001,0.3535))[3535:3537]
3-element Vector{Float64}:
-0.0001
0.0
0.0001
julia> collect(srange(0.0001,0.3535))[begin]
-0.3535
julia> collect(srange(0.0001,0.3535))[end]
0.3535
julia> collect(srange(0.13,0.73))
13-element Vector{Float64}:
-0.78
-0.65
-0.52
-0.39
-0.26
-0.13
0.0
0.13
0.26
0.39
0.52
0.65
0.78
(this will provide the same type of solution the Matlab code provides, I think).
@mbauman …right … hmmm … … then I think that the only requirement then is that it hits zero (based on the MATLAB code)
In that case simply constructing a StepRangeLen
with an offset as described above is your best bet, e.g. zerorange(max, len) = let s=max/len; StepRangeLen(zero(s), s, 2len+1, len+1); end
constructs a range from -max
to max
with 2len+1
points that exactly hits zero.
In the end what I did was this:
function srange(dx, xmax)
n = floor(xmax/dx) |> Int
StepRangeLen(zero(dx), dx, 2n+1, n+1);
end
For others reading this in posterity, here’s some explicit explanation to what @mbauman and others said above. The difficulty here comes from the limited precision of floating point arithmetic. There are two parameters to set in a range
, which can generally satisfy two constraints exactly, and everything else not necessarily exact. Whichever way range
is called, it may be considered equivalent to setting some desired exact point xexact
and an increment dx
. (I’m ignoring the integer length
because the problem is with the floats.)
By default, range
sets the lower limit xexact=xmin
and dx
, and generally won’t hit zero exactly when you add an integer number of steps m*dx
. @Jorge_Vieyra’s srange
solves this by setting xexact=0
, and adding an integer number of dx
s below and above. Of course, that won’t generally hit either the lower and upper limits exactly.
These limits could also be made exact, but that would be equivalent to adding more parameters. For example, one could force x[n+1]=0
, x[1]=xmin
, and x[2*n+1]=xmax
all to be exact, but that means somewhere dx
has to give. It might be that x[2]-x[1] != dx
and x[2*n+1]-x[2*n] != dx
. So those increments would only be close to but not exactly dx
. The additional constraints would require additional parameters, possibly implicit in the algorithm.
In general, each parameter lets you meet one constraint. Whereas range
has two parameters, custom ranges could be designed with more parameters that satisfy more constraints.
The term “generally” refers to possible worst cases. Of course, there are special cases where arithmetic is correct, such as -5.0:1.0:5.0
. An increment of 1.0
is usually safe (not always).
A couple minor points. First, lots of suggestions included collect
, which was only only to display the resulting numbers. In actual computation, you almost never need to collect
, and the range
or other iterator can be operated on directly, avoiding the memory cost of collect
. Second, OP could alternatively do floor(Int, xmax/dx)
rather than the also-correct floor(xmax/dx) |> Int
.