How to create a `range` centered around zero?

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. :slight_smile:

If I remember right, it can sometimes generate a final value that’s greater than your max.

2 Likes

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 … :thinking: … 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.

5 Likes

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
1 Like

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 dxs 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.

5 Likes