Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "RFC: promote ranges to the largest of the the start, step, or length (as applicable)" #43788

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,6 @@ broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::LinRange, x::Number) = LinRa
broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::OrdinalRange, x::AbstractFloat) =
Base.range_start_step_length(first(r)*x, step(r)*x, length(r))

#broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::AbstractRange, x::Number) = range(first(r)/x, last(r)/x, length=length(r))
broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::AbstractRange, x::Number) = range(first(r)/x, step=step(r)/x, length=length(r))
broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::StepRangeLen{T}, x::Number) where {T} =
StepRangeLen{typeof(T(r.ref)/x)}(r.ref/x, r.step/x, length(r), r.offset)
Expand Down
4 changes: 2 additions & 2 deletions base/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ function _hypot(x, y)

# Return Inf if either or both inputs is Inf (Compliance with IEEE754)
if isinf(ax) || isinf(ay)
return typeof(axu)(Inf)
return oftype(axu, Inf)
end

# Order the operands
Expand Down Expand Up @@ -745,7 +745,7 @@ _hypot(x::ComplexF16, y::ComplexF16) = Float16(_hypot(ComplexF32(x), ComplexF32(
function _hypot(x...)
maxabs = maximum(abs, x)
if isnan(maxabs) && any(isinf, x)
return typeof(maxabs)(Inf)
return oftype(maxabs, Inf)
elseif (iszero(maxabs) || isinf(maxabs))
return maxabs
else
Expand Down
112 changes: 56 additions & 56 deletions base/range.jl
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

(:)(a::Real, b::Real) = (:)(promote(a, b)...)
(:)(a::Real, b::Real) = (:)(promote(a,b)...)

(:)(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop)

(:)(start::T, stop::T) where {T} = (:)(start, oftype(stop >= start ? stop - start : start - stop, 1), stop)

# promote start and stop, leaving step alone
(:)(start::A, step, stop::C) where {A<:Real, C<:Real} =
(:)(convert(promote_type(A, C), start), step, convert(promote_type(A, C), stop))
(:)(start::A, step, stop::C) where {A<:Real,C<:Real} =
(:)(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop))

# AbstractFloat specializations
(:)(a::T, b::T) where {T<:AbstractFloat} = (:)(a, T(1), b)

(:)(a::T, b::AbstractFloat, c::T) where {T<:Real} = (:)(promote(a, b, c)...)
(:)(a::T, b::AbstractFloat, c::T) where {T<:AbstractFloat} = (:)(promote(a, b, c)...)
(:)(a::T, b::Real, c::T) where {T<:AbstractFloat} = (:)(promote(a, b, c)...)
(:)(a::T, b::AbstractFloat, c::T) where {T<:Real} = (:)(promote(a,b,c)...)
(:)(a::T, b::AbstractFloat, c::T) where {T<:AbstractFloat} = (:)(promote(a,b,c)...)
(:)(a::T, b::Real, c::T) where {T<:AbstractFloat} = (:)(promote(a,b,c)...)

(:)(start::T, step::T, stop::T) where {T<:AbstractFloat} =
_colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop)
Expand Down Expand Up @@ -167,39 +167,49 @@ range_length(len::Integer) = OneTo(len)
range_stop(stop) = range_start_stop(oftype(stop, 1), stop)
range_stop(stop::Integer) = range_length(stop)

# Stop and length as the only argument
range_stop_length(a::Real, len::Integer) = UnitRange{typeof(a)}(oftype(a, a-len+1), a)
range_stop_length(a::AbstractFloat, len::Integer) = range_step_stop_length(oftype(a, 1), a, len)
range_stop_length(a, len::Integer) = range_step_stop_length(oftype(a-a, 1), a, len)

range_step_stop_length(step, stop, length) = reverse(range_start_step_length(stop, -step, length))

# Stop and length as the only argument
function range_stop_length(a, len::Integer)
step = oftype(a - a, 1) # assert that step is representable
start = a - (len - oneunit(len))
if start isa Signed
# overflow in recomputing length from stop is okay
return UnitRange(start, oftype(start, a))
end
return range_step_stop_length(oftype(a - a, 1), a, len)
range_start_length(a::Real, len::Integer) = UnitRange{typeof(a)}(a, oftype(a, a+len-1))
range_start_length(a::AbstractFloat, len::Integer) = range_start_step_length(a, oftype(a, 1), len)
range_start_length(a, len::Integer) = range_start_step_length(a, oftype(a-a, 1), len)

range_start_stop(start, stop) = start:stop

function range_start_step_length(a::AbstractFloat, step::AbstractFloat, len::Integer)
range_start_step_length(promote(a, step)..., len)
end

# Start and length as the only argument
function range_start_length(a, len::Integer)
step = oftype(a - a, 1) # assert that step is representable
stop = a + (len - oneunit(len))
if stop isa Signed
# overflow in recomputing length from stop is okay
return UnitRange(oftype(stop, a), stop)
end
return range_start_step_length(a, oftype(a - a, 1), len)
function range_start_step_length(a::Real, step::AbstractFloat, len::Integer)
range_start_step_length(float(a), step, len)
end

range_start_stop(start, stop) = start:stop
function range_start_step_length(a::AbstractFloat, step::Real, len::Integer)
range_start_step_length(a, float(step), len)
end

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)
function range_start_step_length(a::T, step::T, len::Integer) where {T <: AbstractFloat}
_rangestyle(OrderStyle(T), ArithmeticStyle(T), a, step, len)
end

function range_start_step_length(a::T, step, len::Integer) where {T}
_rangestyle(OrderStyle(T), ArithmeticStyle(T), a, step, len)
end

function _rangestyle(::Ordered, ::ArithmeticWraps, a, step, len::Integer)
start = a + zero(step)
stop = a + step * (len - 1)
T = typeof(start)
return StepRange{T,typeof(step)}(start, step, convert(T, stop))
end
function _rangestyle(::Any, ::Any, a, step, len::Integer)
start = a + zero(step)
T = typeof(a)
return StepRangeLen{typeof(start),T,typeof(step)}(a, step, len)
end

range_start_step_stop(start, step, stop) = start:step:stop
Expand Down Expand Up @@ -883,7 +893,7 @@ _in_unit_range(v::UnitRange, val, i::Integer) = i > 0 && val <= v.stop && val >=
function getindex(v::UnitRange{T}, i::Integer) where T
@inline
i isa Bool && throw(ArgumentError("invalid index: $i of type Bool"))
val = convert(T, v.start + (i - oneunit(i)))
val = convert(T, v.start + (i - 1))
@boundscheck _in_unit_range(v, val, i) || throw_boundserror(v, i)
val
end
Expand All @@ -894,7 +904,7 @@ const OverflowSafe = Union{Bool,Int8,Int16,Int32,Int64,Int128,
function getindex(v::UnitRange{T}, i::Integer) where {T<:OverflowSafe}
@inline
i isa Bool && throw(ArgumentError("invalid index: $i of type Bool"))
val = v.start + (i - oneunit(i))
val = v.start + (i - 1)
@boundscheck _in_unit_range(v, val, i) || throw_boundserror(v, i)
val % T
end
Expand All @@ -909,7 +919,7 @@ end
function getindex(v::AbstractRange{T}, i::Integer) where T
@inline
i isa Bool && throw(ArgumentError("invalid index: $i of type Bool"))
ret = convert(T, first(v) + (i - oneunit(i))*step_hp(v))
ret = convert(T, first(v) + (i - 1)*step_hp(v))
ok = ifelse(step(v) > zero(step(v)),
(ret <= last(v)) & (ret >= first(v)),
(ret <= first(v)) & (ret >= last(v)))
Expand Down Expand Up @@ -939,14 +949,13 @@ end

function unsafe_getindex(r::LinRange, i::Integer)
i isa Bool && throw(ArgumentError("invalid index: $i of type Bool"))
lerpi(i-oneunit(i), r.lendiv, r.start, r.stop)
lerpi(i-1, r.lendiv, r.start, r.stop)
end

function lerpi(j::Integer, d::Integer, a::T, b::T) where T
@inline
t = j/d # ∈ [0,1]
# compute approximately fma(t, b, -fma(t, a, a))
return T((1-t)*a + t*b)
t = j/d
T((1-t)*a + t*b)
end

getindex(r::AbstractRange, ::Colon) = copy(r)
Expand All @@ -959,10 +968,8 @@ function getindex(r::AbstractUnitRange, s::AbstractUnitRange{T}) where {T<:Integ
return range(first(s) ? first(r) : last(r), length = last(s))
else
f = first(r)
start = oftype(f, f + first(s) - firstindex(r))
len = length(s)
stop = oftype(f, start + (len - oneunit(len)))
return range(start, stop)
start = oftype(f, f + first(s)-firstindex(r))
return range(start, length=length(s))
end
end

Expand All @@ -977,14 +984,11 @@ function getindex(r::AbstractUnitRange, s::StepRange{T}) where {T<:Integer}
@boundscheck checkbounds(r, s)

if T === Bool
return range(first(s) ? first(r) : last(r), step=oneunit(eltype(r)), length=last(s))
return range(first(s) ? first(r) : last(r), step=oneunit(eltype(r)), length = last(s))
else
f = first(r)
start = oftype(f, f + s.start - firstindex(r))
st = step(s)
len = length(s)
stop = oftype(f, start + (len - oneunit(len)) * st)
return range(start, stop; step=st)
start = oftype(f, f + s.start-firstindex(r))
return range(start, step=step(s), length=length(s))
end
end

Expand All @@ -1007,13 +1011,9 @@ function getindex(r::StepRange, s::AbstractRange{T}) where {T<:Integer}
return range(start, step=step(r); length=len)
else
f = r.start
fs = first(s)
st = r.step
start = oftype(f, f + (fs - oneunit(fs)) * st)
st = st * step(s)
len = length(s)
stop = oftype(f, start + (len - oneunit(len)) * st)
return range(start, stop; step=st)
start = oftype(f, f + (first(s)-oneunit(first(s)))*st)
return range(start; step=st*step(s), length=length(s))
end
end

Expand Down Expand Up @@ -1042,7 +1042,7 @@ function getindex(r::StepRangeLen{T}, s::OrdinalRange{S}) where {T, S<:Integer}
# Find closest approach to offset by s
ind = LinearIndices(s)
offset = L(max(min(1 + round(L, (r.offset - first(s))/sstep), last(ind)), first(ind)))
ref = _getindex_hiprec(r, first(s) + (offset - oneunit(offset)) * sstep)
ref = _getindex_hiprec(r, first(s) + (offset-1)*sstep)
return StepRangeLen{T}(ref, rstep*sstep, len, offset)
end
end
Expand Down
6 changes: 4 additions & 2 deletions stdlib/Dates/test/periods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,10 @@ end
@test_throws InexactError y * 3//4
@test (1:1:5)*Second(5) === Second(5)*(1:1:5) === Second(5):Second(5):Second(25) === (1:5)*Second(5)
@test collect(1:1:5)*Second(5) == Second(5)*collect(1:1:5) == (1:5)*Second(5)
@test (Second(2):Second(2):Second(10))/Second(2) === 1.0:1.0:5.0 == collect(Second(2):Second(2):Second(10))/Second(2)
@test (Second(2):Second(2):Second(10)) / 2 == Second(1):Second(1):Second(5) == collect(Second(2):Second(2):Second(10)) / 2
@test (Second(2):Second(2):Second(10))/Second(2) === 1.0:1.0:5.0
@test collect(Second(2):Second(2):Second(10))/Second(2) == 1:1:5
@test (Second(2):Second(2):Second(10)) / 2 === Second(1):Second(1):Second(5)
@test collect(Second(2):Second(2):Second(10)) / 2 == Second(1):Second(1):Second(5)
@test Dates.Year(4) / 2 == Dates.Year(2)
@test Dates.Year(4) / 2f0 == Dates.Year(2)
@test Dates.Year(4) / 0.5 == Dates.Year(8)
Expand Down
18 changes: 6 additions & 12 deletions stdlib/LinearAlgebra/test/special.jl
Original file line number Diff line number Diff line change
Expand Up @@ -375,18 +375,12 @@ using .Main.Furlongs
@test one(S) isa SymTridiagonal

# eltype with dimensions
D0 = Diagonal{Furlong{0, Int64}}([1, 2, 3, 4])
Bu0 = Bidiagonal{Furlong{0, Int64}}([1, 2, 3, 4], [1, 2, 3], 'U')
Bl0 = Bidiagonal{Furlong{0, Int64}}([1, 2, 3, 4], [1, 2, 3], 'L')
T0 = Tridiagonal{Furlong{0, Int64}}([1, 2, 3], [1, 2, 3, 4], [1, 2, 3])
S0 = SymTridiagonal{Furlong{0, Int64}}([1, 2, 3, 4], [1, 2, 3])
F2 = Furlongs.Furlong{2}(1)
D2 = Diagonal{Furlong{2, Int64}}([1, 2, 3, 4].*F2)
Bu2 = Bidiagonal{Furlong{2, Int64}}([1, 2, 3, 4].*F2, [1, 2, 3].*F2, 'U')
Bl2 = Bidiagonal{Furlong{2, Int64}}([1, 2, 3, 4].*F2, [1, 2, 3].*F2, 'L')
T2 = Tridiagonal{Furlong{2, Int64}}([1, 2, 3].*F2, [1, 2, 3, 4].*F2, [1, 2, 3].*F2)
S2 = SymTridiagonal{Furlong{2, Int64}}([1, 2, 3, 4].*F2, [1, 2, 3].*F2)
mats = Any[D0, Bu0, Bl0, T0, S0, D2, Bu2, Bl2, T2, S2]
D = Diagonal{Furlong{2, Int64}}([1, 2, 3, 4])
Bu = Bidiagonal{Furlong{2, Int64}}([1, 2, 3, 4], [1, 2, 3], 'U')
Bl = Bidiagonal{Furlong{2, Int64}}([1, 2, 3, 4], [1, 2, 3], 'L')
T = Tridiagonal{Furlong{2, Int64}}([1, 2, 3], [1, 2, 3, 4], [1, 2, 3])
S = SymTridiagonal{Furlong{2, Int64}}([1, 2, 3, 4], [1, 2, 3])
mats = [D, Bu, Bl, T, S]
for A in mats
@test iszero(zero(A))
@test isone(one(A))
Expand Down
22 changes: 2 additions & 20 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1525,10 +1525,8 @@ isdefined(Main, :Furlongs) || @eval Main include("testhelpers/Furlongs.jl")
using .Main.Furlongs

@testset "dimensional correctness" begin
@test_throws TypeError Furlong(2):Furlong(10)
@test_throws TypeError range(Furlong(2), length=9)
@test length(Vector(Furlong(2):Furlong(1):Furlong(10))) == 9
@test length(range(Furlong(2), step=Furlong(1), length=9)) == checked_length(range(Furlong(2), step=Furlong(1), length=9)) == 9
@test length(Vector(Furlong(2):Furlong(10))) == 9
@test length(range(Furlong(2), length=9)) == checked_length(range(Furlong(2), length=9)) == 9
@test @inferred(length(StepRange(Furlong(2), Furlong(1), Furlong(1)))) == 0
@test Vector(Furlong(2):Furlong(1):Furlong(10)) == Vector(range(Furlong(2), step=Furlong(1), length=9)) == Furlong.(2:10)
@test Vector(Furlong(1.0):Furlong(0.5):Furlong(10.0)) ==
Expand Down Expand Up @@ -2267,19 +2265,3 @@ let r = Ptr{Cvoid}(20):-UInt(2):Ptr{Cvoid}(10)
@test step(r) === -UInt(2)
@test last(r) === Ptr{Cvoid}(10)
end

# test behavior of wrap-around and promotion of empty ranges (#35711)
@test length(range(0, length=UInt(0))) === UInt(0)
@test isempty(range(0, length=UInt(0)))
@test length(range(typemax(Int), length=UInt(0))) === UInt(0)
@test isempty(range(typemax(Int), length=UInt(0)))
@test length(range(0, length=UInt(0), step=UInt(2))) == UInt(0)
@test isempty(range(0, length=UInt(0), step=UInt(2)))
@test length(range(typemax(Int), length=UInt(0), step=UInt(2))) === UInt(0)
@test isempty(range(typemax(Int), length=UInt(0), step=UInt(2)))
@test length(range(typemax(Int), length=UInt(0), step=2)) === UInt(0)
@test isempty(range(typemax(Int), length=UInt(0), step=2))
@test length(range(typemax(Int), length=0, step=UInt(2))) === 0
@test isempty(range(typemax(Int), length=0, step=UInt(2)))

@test length(range(1, length=typemax(Int128))) === typemax(Int128)
17 changes: 2 additions & 15 deletions test/testhelpers/Furlongs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,13 @@ end
Furlong(x::T) where {T<:Number} = Furlong{1,T}(x)
Furlong(x::Furlong) = x
(::Type{T})(x::Furlong{0}) where {T<:Number} = T(x.val)::T
(::Type{T})(x::Furlong{0}) where {T<:Furlong{0}} = T(x.val)::T
(::Type{T})(x::Furlong{0}) where {T<:Furlong} = typeassert(x, T)
Furlong{p}(v::Number) where {p} = Furlong{p,typeof(v)}(v)
Furlong{p}(x::Furlong{q}) where {p,q} = (typeassert(x, Furlong{p}); Furlong{p,typeof(x.val)}(x.val))
Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (typeassert(x, Furlong{p}); Furlong{p,T}(T(x.val)))
Furlong{p}(x::Furlong{q}) where {p,q} = (@assert(p==q); Furlong{p,typeof(x.val)}(x.val))
Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (@assert(p==q); Furlong{p,T}(T(x.val)))

Base.promote_type(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} =
Furlong{p,promote_type(T,S)}

# only Furlong{0} forms a ring and isa Number
Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y)
Base.convert(::Type{Furlong}, y::Number) = Furlong{0}(y)
Base.convert(::Type{Furlong{<:Any,T}}, y::Number) where {T<:Number} = Furlong{0,T}(y)
Base.convert(::Type{T}, y::Number) where {T<:Furlong} = typeassert(y, T) # throws, since cannot convert a Furlong{0} to a Furlong{p}
# other Furlong{p} form a group
Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)
Base.convert(::Type{Furlong}, y::Furlong) = y
Base.convert(::Type{Furlong{<:Any,T}}, y::Furlong{p}) where {p,T<:Number} = Furlong{p,T}(y)
Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)

Base.one(x::Furlong{p,T}) where {p,T} = one(T)
Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T)
Base.oneunit(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(one(T))
Expand Down