Skip to content

Commit

Permalink
Merge pull request #113 from ajkeller34/rangefix
Browse files Browse the repository at this point in the history
Some fixes for #111
  • Loading branch information
ajkeller34 authored Dec 6, 2017
2 parents e6f35cb + 4c1a227 commit 3d5fbb7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/Unitful.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Base: eps, mod, rem, div, fld, cld, trunc, round, sign, signbit
import Base: isless, isapprox, isinteger, isreal, isinf, isfinite, isnan
import Base: copysign, flipsign
import Base: prevfloat, nextfloat, maxintfloat, rat, step
import Base: length, float, start, done, next, last, one, zero, colon
import Base: length, float, start, done, next, last, one, zero, colon, range
import Base: getindex, eltype, step, last, first, frexp
import Base: Integer, Rational, typemin, typemax
import Base: steprange_last, unsigned
Expand Down
41 changes: 34 additions & 7 deletions src/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@ function _linspace(start::Quantity{T}, stop::Quantity{T}, len::Integer) where {T
dimension(start) != dimension(stop) && throw(DimensionError(start, stop))
linspace(start, stop, len)
end
# first promote start and stop, leaving step alone
colon(start::A, step, stop::C) where {A<:Real,C<:Quantity} = colonstartstop(start,step,stop)
colon(start::A, step, stop::C) where {A<:Quantity,C<:Real} = colonstartstop(start,step,stop)
colon(a::T, b::Quantity, c::T) where {T<:Real} = colon(promote(a,b,c)...)
colon(start::Quantity{<:Real}, step, stop::Quantity{<:Real}) =
colon(promote(start, step, stop)...)

function colon(start::Quantity{<:Real}, step, stop::Quantity{<:Real})
# promotes start and stop
function colonstartstop(start::A, step, stop::C) where {A,C}
dimension(start) != dimension(stop) && throw(DimensionError(start, stop))
T = promote_type(typeof(start),typeof(stop))
return colon(convert(T,start), step, convert(T,stop))
colon(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop))
end

function colon(start::A, step::B, stop::A) where A<:Quantity{<:Real} where B<:Quantity{<:Real}
Expand Down Expand Up @@ -50,18 +56,39 @@ _colon(::Any, ::Any, start::T, step, stop::T) where {T} =
*(x::Base.TwicePrecision, y::Units) = Base.TwicePrecision(x.hi*y, x.lo*y)
*(x::Base.TwicePrecision, y::Quantity) = (x * ustrip(y)) * unit(y)
function colon(start::T, step::T, stop::T) where (T<:Quantity{S}
where S<:Union{Float16,Float32,Float64})
where S<:Union{Float16,Float32,Float64})
# This will always return a StepRangeLen
r = colon(ustrip(start), ustrip(step), ustrip(stop))
return r*unit(T)
return colon(ustrip(start), ustrip(step), ustrip(stop)) * unit(T)
end
function Base.linspace(start::T, stop::T, len::Integer) where (T<:Quantity{S}
where S<:Union{Float16,Float32,Float64})
linspace(ustrip(start), ustrip(stop), len)*unit(T)
linspace(ustrip(start), ustrip(stop), len) * unit(T)
end

# No need to confuse things by changing the type once units are on there,
# if we can help it.
*(r::StepRangeLen, y::Units) = StepRangeLen(r.ref*y, r.step*y, length(r), r.offset)
*(r::LinSpace, y::Units) = LinSpace(r.start*y, r.stop*y, length(r))
*(r::StepRange, y::Units) = StepRange(r.start*y, r.step*y, r.stop*y)

function range(a::T, st::T, len::Integer) where (T<:Quantity{S}
where S<:Union{Float16,Float32,Float64})
return range(ustrip(a), ustrip(st), len) * unit(T)
end
range(a::Quantity{<:Real}, st::Quantity{<:AbstractFloat}, len::Integer) =
range(float(a), st, len)
range(a::Quantity{<:AbstractFloat}, st::Quantity{<:Real}, len::Integer) =
range(a, float(st), len)
range(a::Quantity{<:AbstractFloat}, st::Quantity{<:AbstractFloat}, len::Integer) =
_range(promote(a, st)..., len)
_range(a::T, st::T, len) where {T<:Quantity} = range(a, st, len)
_range(a, st, len) = throw(DimensionError(a, st))

range(a::Quantity, st::Real, len::Integer) = range(promote(a, st)..., len)
range(a::Real, st::Quantity, len::Integer) = range(promote(a, st)..., len)

# the following is needed to give sane error messages when doing e.g. range(1°, 2V, 5)
function range(a::T, step, len::Integer) where {T<:Quantity}
dimension(a) != dimension(step) && throw(DimensionError(a,step))
return Base._range(TypeOrder(T), TypeArithmetic(T), a, step, len)
end
37 changes: 27 additions & 10 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -846,17 +846,39 @@ end
@test typeof((1m:2m:13m)[2:3:7]) == typeof(3m:6m:13m)
end
@testset ">> StepRange" begin
r = @inferred(colon(1m, 1m, 5m)) # 1m:1m:5m
@test isa(r, StepRange)
r = @inferred(colon(1m, 1m, 5m))
@test isa(r, StepRange{typeof(1m)})
@test @inferred(length(r)) === 5
@test @inferred(step(r)) === 1m

@test @inferred(first(range(1mm, 2m, 4))) === 1mm
@test @inferred(step(range(1mm, 2m, 4))) === 2m
@test @inferred(last(range(1mm, 2m, 4))) === 6001mm
@test_throws ArgumentError 1m:0m:5m

@test_throws DimensionError range(1m, 2V, 5)
try
range(1m, 2V, 5)
catch e
@test e.x == 1m
@test e.y == 2V
end
end
@testset ">> Float StepRange" begin
# @test isa(@inferred(colon(1.0m, 1m, 5m)), StepRange{typeof(1.0m)})
@testset ">> StepRangeLen" begin
@test isa(@inferred(colon(1.0m, 1m, 5m)), StepRangeLen{typeof(1.0m)})
@test @inferred(length(1.0m:1m:5m)) === 5
@test @inferred(step(1.0m:1m:5m)) === 1.0m

@test @inferred(length(0:10°:360°)) == 37 # issue 111
@test @inferred(length(0.0:10°:2pi)) == 37 # issue 111 fallout
@test @inferred(last(0°:0.1:360°)) === 6.2 # issue 111 fallout

@test @inferred(first(range(1mm, 0.1mm, 50))) === 1.0mm # issue 111
@test @inferred(step(range(1mm, 0.1mm, 50))) === 0.1mm # issue 111
@test @inferred(last(range(0,10°,37))) == 2pi
@test @inferred(last(range(0°,2pi/36,37))) == 2pi
@test_throws ArgumentError 1.0m:0.0m:5.0m
@test_throws DimensionError range(1.0m, 1.0V, 5)
@test step(range(1.0m, 1m, 5)) === 1.0m
end
@testset ">> LinSpace" begin
@test isa(@inferred(linspace(1.0m, 3.0m, 5)),
Expand All @@ -870,11 +892,6 @@ end
@test_throws Unitful.DimensionError linspace(1m, 10, 5)
@test_throws Unitful.DimensionError linspace(1, 10m, 5)
end
@testset ">> Range → Range" begin
# @test isa((1m:5m)*2, StepRange)
# @test isa((1m:5m)/2, FloatRange)
# @test isa((1m:2m:5m)/2, FloatRange)
end
@testset ">> Range → Array" begin
@test isa(collect(1m:1m:5m), Array{typeof(1m),1})
@test isa(collect(1m:2m:10m), Array{typeof(1m),1})
Expand Down

0 comments on commit 3d5fbb7

Please sign in to comment.