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

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 … … 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 `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`.

5 Likes