How to slightly extend a range?


Suppose I have a range:

r = 1:10

I found a function to extend the range:

extended_range(r,δ) = (first(r) - δ):step(r):(last(r) + δ)

But I observe some different behaviours:



It works as intended with a large number, but not with a very small number. Is what I request possible to do in some way?

The left part, 0.99999…8 is correct and what I want. For 10.0 I would have wanted 10.000…2

Kind regards

May I ask why you must only extend by eps()?

Inspired by code here:

I am trying to optimize this function to avoid using collect. My version uses vcat below:

""" Sums the cycle count given intervals of range_intervals and mean_intervals. The range_intervals and mean_intervals is given in fraction of range size"""
function sum_cycles(cycles::Vector{Cycle{T}}, range_intervals::Interval{T}, mean_intervals::Interval{T}) where {T <: Real}
    bounds   = find_boundary_vals(cycles)
    bins     = zeros(length(range_intervals)-1, length(mean_intervals)-1)
    range_in = (range_intervals*bounds.max_range)/100
    mean_in  = (mean_intervals*(bounds.max_mean-bounds.min_mean))/100
    mean_in  = mean_in .+ bounds.min_mean
    @assert issorted(mean_intervals)  "The array needs to be sorted in raising order"
    @assert issorted(range_intervals) "The array needs to be sorted in raising order"

    mean_i  = vcat(mean_in)
    range_i = vcat(range_in)
    #ensure the cycles is in the intervals by adding a small error to the end values of the interal.
    error_m = (bounds.max_mean-bounds.min_mean) #instead of 1e-14 - The rounding is performed due to numerical noise in the floats when comparing
    error_r = bounds.max_range #instead of 1e-14

    @inbounds for cycle in cycles
        i = find_range(range_i, cycle.range)
        j = find_range(mean_i, cycle.mean)
        bins[i,j] += cycle.count
    return bins

Trying to see if I can make the code a bit prettier/faster, by extending the range slightly through a function.

Kind regards

It doesn’t look like one must use eps() for this? Just use a small number like 10^-12 your original approach should be fine

It is not:



It is decreasing range, when it should be extending it

May I ask why you keep the same step? That looks / reads strange to me mathematically and might explain your (strange) end points…

If you have 1:10 your step is 1.0, if you now try to use your function (let me take a more extreme δ) with δ=0.25
you would take as first point 0.75 but still steps of size 1, so you would not reach your desired end of 10.25 but only 9.75?

edit: You could keep the length (instead of keeping the step), then the step is adapted automatically, e.g.

julia> extend_range2(r,δ) = range(start=first(r)-δ, stop=last(r)+δ, length=length(r))
extend_range2 (generic function with 1 method)

julia> extend_range2(1:10, 0.25)
1 Like

Couple things to be aware about:

  1. Ranges compute the inclusive endpoints during construction, so if your step is too large, adjusting the likely exclusive input endpoint won’t make a difference
julia> 1:2:8.0, 1:2:8.01
(1.0:2.0:7.0, 1.0:2.0:7.0)

The intention is that the same sequence is represented by the same instance for comparison, even if the input values (3 of start, step, stop, or length) are different.

  1. Adding eps(Float64) to 10 is actually doing nothing. You probably intended to add the smallest difference, but the thing about floating points is that difference depends on the absolute value. eps(Float64) does the difference for 1.0, and that is smaller than the difference for 10.0.
julia> eps(Float64), eps(1.0), eps(10.0)
(2.220446049250313e-16, 2.220446049250313e-16, 1.7763568394002505e-15)

julia> (10 + eps(Float64)) - 10

julia> (10 + eps(10.0)) - 10