-
Notifications
You must be signed in to change notification settings - Fork 116
/
Copy pathrange.jl
96 lines (86 loc) · 4.94 KB
/
range.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
const colon = Base.:(:)
import Base: ArithmeticRounds
import Base: OrderStyle, Ordered, ArithmeticStyle, ArithmeticWraps
*(y::Units, r::AbstractRange) = *(r,y)
*(r::AbstractRange, y::Units, z::Units...) = *(r, *(y,z...))
Base._range(start::Quantity{<:Real}, ::Nothing, stop, len::Integer) =
_range(promote(start, stop)..., len)
Base._range(start, ::Nothing, stop::Quantity{<:Real}, len::Integer) =
_range(promote(start, stop)..., len)
Base._range(start::Quantity{<:Real}, ::Nothing, stop::Quantity{<:Real}, len::Integer) =
_range(promote(start, stop)..., len)
(Base._range(start::T, ::Nothing, stop::T, len::Integer) where (T<:Quantity{<:Real})) =
LinRange{T}(start, stop, len)
(Base._range(start::T, ::Nothing, stop::T, len::Integer) where (T<:Quantity{<:Integer})) =
Base._linspace(Float64, ustrip(start), ustrip(stop), len, 1)*unit(T)
function Base._range(start::T, ::Nothing, stop::T, len::Integer) where (T<:Quantity{S}
where S<:Union{Float16,Float32,Float64})
range(ustrip(start), stop=ustrip(stop), length=len) * unit(T)
end
function _range(start::Quantity{T}, stop::Quantity{T}, len::Integer) where {T}
dimension(start) != dimension(stop) && throw(DimensionError(start, stop))
Base._range(start, nothing, stop, len)
end
function Base._range(a::T, st::T, ::Nothing, len::Integer) where (T<:Quantity{S}
where S<:Union{Float16,Float32,Float64})
return Base._range(ustrip(a), ustrip(st), nothing, len) * unit(T)
end
Base._range(a::Quantity{<:Real}, st::Quantity{<:AbstractFloat}, ::Nothing, len::Integer) =
Base._range(float(a), st, nothing, len)
Base._range(a::Quantity{<:AbstractFloat}, st::Quantity{<:Real}, ::Nothing, len::Integer) =
Base._range(a, float(st), nothing, len)
function Base._range(a::Quantity{<:AbstractFloat}, st::Quantity{<:AbstractFloat}, ::Nothing, len::Integer)
dimension(a) != dimension(st) && throw(DimensionError(a, st))
Base._range(promote(a, uconvert(unit(a), st))..., nothing, len)
end
Base._range(a::Quantity, st::Real, ::Nothing, len::Integer) =
Base._range(promote(a, uconvert(unit(a), st))..., nothing, len)
Base._range(a::Real, st::Quantity, ::Nothing, len::Integer) =
Base._range(promote(a, uconvert(unit(a), st))..., nothing, len)
# the following is needed to give sane error messages when doing e.g. range(1°, 2V, 5)
function Base._range(a::Quantity, step, ::Nothing, len::Integer)
dimension(a) != dimension(step) && throw(DimensionError(a,step))
_a, _step = promote(a, uconvert(unit(a), step))
return Base._rangestyle(OrderStyle(_a), ArithmeticStyle(_a), _a, _step, len)
end
*(r::AbstractRange, y::Units) = range(first(r)*y, step=step(r)*y, length=length(r))
# 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)...)
# promotes start and stop
function colonstartstop(start::A, step, stop::C) where {A,C}
dimension(start) != dimension(stop) && throw(DimensionError(start, 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}
dimension(start) != dimension(step) && throw(DimensionError(start, step))
colon(promote(start, step, stop)...)
end
OrderStyle(::Type{<:AbstractQuantity{T}}) where T = OrderStyle(T)
ArithmeticStyle(::Type{<:AbstractQuantity{T}}) where T = ArithmeticStyle(T)
(colon(start::T, step::T, stop::T) where T <: Quantity{<:Real}) =
_colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop)
_colon(::Ordered, ::Any, start::T, step, stop::T) where {T} = StepRange(start, step, stop)
_colon(::Ordered, ::ArithmeticRounds, start::T, step, stop::T) where {T} =
StepRangeLen(start, step, floor(Int, (stop-start)/step)+1)
_colon(::Any, ::Any, start::T, step, stop::T) where {T} =
StepRangeLen(start, step, floor(Int, (stop-start)/step)+1)
# Opt into TwicePrecision functionality
*(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})
# This will always return a StepRangeLen
return colon(ustrip(start), ustrip(step), ustrip(stop)) * 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::LinRange, y::Units) = LinRange(r.start*y, r.stop*y, length(r))
*(r::StepRange, y::Units) = StepRange(r.start*y, r.step*y, r.stop*y)
function /(x::Base.TwicePrecision, v::Quantity)
x / Base.TwicePrecision(oftype(ustrip(x.hi)/ustrip(v)*unit(v), v))
end