Skip to content

range(start::Int; step, length) no longer uses TwicePrecision #44292

@jipolanco

Description

@jipolanco
Contributor

Not sure if this is considered a regression, but the following:

r = range(0; step = 0.2, length = 5)
collect(r)  # [0.0, 0.2, 0.4, 0.6, 0.8]                on Julia 1.7
collect(r)  # [0.0, 0.2, 0.4, 0.6000000000000001, 0.8] on Julia 1.8 / master

returns a StepRangeLen{Float64, Int64, Float64, Int64} on Julia master / 1.8, while it used to return a StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64} on Julia 1.7.

I guess this change of behaviour is in conflict with the statement in the range docs:

Special care is taken to ensure intermediate values are computed rationally. To avoid this induced overhead, see the LinRange constructor.

Note that this doesn't happen when start is a float (more specifically, it must be a Union{Float16,Float32,Float64} and have the same type as step), and therefore changing 0 by 0.0 in the above example works around the issue (so that the range_start_step_length function defined in twiceprecision.jl is called).


This change of behaviour seems to be introduced by #43059, and more precisely in the new definition of the range_start_step_length function copied below. From what I understand, that PR aimed at fixing issues dealing with integer ranges (but I might be wrong about this...). In any case, the branch if stop isa Signed is always skipped if step is a float, in which case stop is also a float.

function range_start_step_length(a, step, len::Integer)
    stop = a + step * (len - oneunit(len))
    if stop isa Signed
        # overflow in recomputing length from stop is okay
        return StepRange{typeof(stop),typeof(step)}(convert(typeof(stop), a), step, stop)
    end
    return StepRangeLen{typeof(stop),typeof(a),typeof(step)}(a, step, len)
end

So, I guess an easy fix would be to add a specialisation such as:

function range_start_step_length(a, step::Union{Float16,Float32,Float64}, len::Integer)
    return range_start_stop_length(oftype(step, a), step, len)
end

which will end up calling the appropriate function from twiceprecision.jl. Is there any reason why this wouldn't be a good idea?

Activity

added a commit that references this issue on Feb 21, 2022
added this to the 1.8 milestone on Feb 21, 2022
added
rangesEverything AbstractRange
regressionRegression in behavior compared to a previous version
on Feb 21, 2022
vtjnash

vtjnash commented on Feb 22, 2022

@vtjnash
SponsorMember

That sounds right. You are right that I neglected to properly update the range_start_step_length constructor in #43059 to reflect the other changes there.

jipolanco

jipolanco commented on Feb 23, 2022

@jipolanco
ContributorAuthor

Great thanks, I'll make a PR then.

added a commit that references this issue on Feb 23, 2022
1b47efb
added a commit that references this issue on Feb 24, 2022
b9982a8
added a commit that references this issue on Mar 2, 2022
0209c30
added a commit that references this issue on Mar 7, 2022
b8cd730
added a commit that references this issue on Mar 8, 2022
675a51b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    rangesEverything AbstractRangeregressionRegression in behavior compared to a previous version

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Participants

      @vtjnash@KristofferC@jipolanco@dkarrasch

      Issue actions

        `range(start::Int; step, length)` no longer uses TwicePrecision · Issue #44292 · JuliaLang/julia