This is not Julia-specific, it’s due to the fact that standard floating-point arithmetic doesn’t exactly represent decimal values like 1.1 and 0.1. For example, in Python 3:
my particular problem is
The output print 4 elements
0.9000000000000001
1.0000000000000002
1.1
1.2000000000000002
I’m expecting 5 elements
0.9
1.0
1.1
1.2
1.3
This is an intrinsic problem with floating-point ranges, unfortunately — due to roundoff errors perturbing the endpoints, it can change the number of points by 1.
The solution is to explicitly specify the desired length, with range(x-2h, step=h, length=5), or range(x-2h, x+2h, length=5), or LinRange(x-2h, x+2h, 5). (range and LinRange compute their elements in slightly different ways.)
Another option is using StepRangeLen directly with the offset argument. This should be more precise than LinRange. (For x = 1.1, h = 0.1, it produces the same values as LinRange. But in other cases, it might not.)
range creates a StepRangeLen (in this case), but without using offset. This forces you to use x-2h or x+2h as the reference value, with possible loss of precision:
This is close in spirit to your original formulation but does the range with integers to ensure five elements. And you don’t need much knowledge about Julia’s range types.
julia> x = 1.1; h = 0.1;
julia> xlist = x .+ (-2:1:2)*h
0.9000000000000001:0.1:1.3
julia> collect(xlist)
5-element Vector{Float64}:
0.9000000000000001
1.0
1.1
1.2000000000000002
1.3
I would argue it is doing it correctly, it’s as precise as it can be with the information it is given.
range(x-2h, x+2h, 5) doesn’t know about the original x and h, it only sees the results of the computations x-2h and x+2h, both of which are not exact (due to floating-point arithmetic). Therefore, range(x-2h, x+2h, 5) does not necessarily create a range with step h, or one that contains x.
Of course, this loss of precision may not be important, so using range is perfectly fine. I just wanted to mention StepRangeLen with offset as probably the most precise option for a given x and h.