From 0209c30bc920e732a04adfbacdd28376834cc912 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Polanco Date: Wed, 23 Feb 2022 21:07:30 +0100 Subject: [PATCH] Make sure `range(start; step, length)` uses TwicePrecision when possible, fixes #44292. (#44313) --- base/twiceprecision.jl | 12 ++++++++++-- test/ranges.jl | 12 ++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 8f80b2c8438a03..6d91431e47abbb 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -408,7 +408,7 @@ function floatrange(a::AbstractFloat, st::AbstractFloat, len::Real, divisor::Abs steprangelen_hp(T, (a,divisor), (st,divisor), nbitslen(T, len, 1), len, oneunit(len)) end -function (:)(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float64} +function (:)(start::T, step::T, stop::T) where T<:IEEEFloat step == 0 && throw(ArgumentError("range step cannot be zero")) # see if the inputs have exact rational approximations (and if so, # perform all computations in terms of the rationals) @@ -453,7 +453,10 @@ end step(r::StepRangeLen{T,TwicePrecision{T},TwicePrecision{T}}) where {T<:AbstractFloat} = T(r.step) step(r::StepRangeLen{T,TwicePrecision{T},TwicePrecision{T}}) where {T} = T(r.step) -function range_start_step_length(a::T, st::T, len::Integer) where T<:Union{Float16,Float32,Float64} +range_start_step_length(a, st::IEEEFloat, len::Integer) = + range_start_step_length(oftype(st, a), st, len) + +function range_start_step_length(a::T, st::T, len::Integer) where T<:IEEEFloat len = len + 0 # promote with Int start_n, start_d = rat(a) step_n, step_d = rat(st) @@ -471,6 +474,11 @@ function range_start_step_length(a::T, st::T, len::Integer) where T<:Union{Float steprangelen_hp(T, a, st, 0, len, 1) end +function range_step_stop_length(step::IEEEFloat, stop, len::Integer) + r = range_start_step_length(stop, negate(step), len) + reverse(r) +end + # This assumes that r.step has already been split so that (0:len-1)*r.step.hi is exact function unsafe_getindex(r::StepRangeLen{T,<:TwicePrecision,<:TwicePrecision}, i::Integer) where T # Very similar to _getindex_hiprec, but optimized to avoid a 2nd call to add12 diff --git a/test/ranges.jl b/test/ranges.jl index a7f26c7efa6296..536c1f4710d9d1 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -1612,6 +1612,18 @@ end @test x isa StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}} end +@testset "Issue #44292" begin + let x = @inferred range(0, step=0.2, length=5) + @test x isa StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}} + @test x == [0.0, 0.2, 0.4, 0.6, 0.8] + end + + let x = @inferred range(stop=1, step=0.2, length=5) + @test x isa StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}} + @test x == [0.2, 0.4, 0.6, 0.8, 1.0] + end +end + @testset "Views of ranges" begin @test view(Base.OneTo(10), Base.OneTo(5)) === Base.OneTo(5) @test view(1:10, 1:5) === 1:5