From f1f0ef615a494667b7e1439de4db1856afd4d48b Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Mon, 26 May 2014 16:32:17 -0400 Subject: [PATCH 1/2] add +/- for FloatRange (fix #6973) --- base/operators.jl | 33 +++++++++++++++++++++++++++++++++ base/range.jl | 21 ++++++++++----------- test/ranges.jl | 9 +++++++++ 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/base/operators.jl b/base/operators.jl index 98ede76cd482f..1c1b3a7cd9d80 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -313,6 +313,39 @@ to_index(I::(Any,Any,Any,Any)) = (to_index(I[1]), to_index(I[2]), to_index(I[3]) to_index(I::Tuple) = map(to_index, I) to_index(i) = error("invalid index: $i") +# Addition/subtraction of ranges +for f in (:+, :-) + @eval begin + function $f(r1::OrdinalRange, r2::OrdinalRange) + r1l = length(r1) + r1l == length(r2) || error("argument dimensions must match") + range($f(r1.start,r2.start), $f(step(r1),step(r2)), r1l) + end + + function $f{T}(r1::FloatRange{T}, r2::FloatRange{T}) + len = r1.len + len == r2.len || error("argument dimensions must match") + divisor1, divisor2 = r1.divisor, r2.divisor + if divisor1 == divisor2 + FloatRange{T}($f(r1.start,r2.start), $f(r1.step,r2.step), + len, divisor1) + else + d1 = int(divisor1) + d2 = int(divisor2) + d = lcm(d1,d2) + s1 = div(d,d1) + s2 = div(d,d2) + FloatRange{T}($f(r1.start*s1, r2.start*s2), + $f(r1.step*s1, r2.step*s2), len, d) + end + end + + $f(r1::FloatRange, r2::FloatRange) = $f(promote(r1,r2)...) + $f(r1::FloatRange, r2::OrdinalRange) = $f(promote(r1,r2)...) + $f(r1::OrdinalRange, r2::FloatRange) = $f(promote(r1,r2)...) + end +end + # vectorization macro vectorize_1arg(S,f) diff --git a/base/range.jl b/base/range.jl index 43b1b75c91c95..97a1f42e54510 100644 --- a/base/range.jl +++ b/base/range.jl @@ -437,18 +437,17 @@ end ./(r::OrdinalRange, x::Real) = range(r.start/x, step(r)/x, length(r)) ./(r::FloatRange, x::Real) = FloatRange(r.start/x, r.step/x, r.len, r.divisor) -# TODO: better implementations for FloatRanges? -function +(r1::OrdinalRange, r2::OrdinalRange) - r1l = length(r1) - r1l == length(r2) || error("argument dimensions must match") - range(r1.start+r2.start, step(r1)+step(r2), r1l) -end +promote_rule{T1,T2}(::Type{FloatRange{T1}},::Type{FloatRange{T2}}) = + FloatRange{promote_type(T1,T2)} +convert{T}(::Type{FloatRange{T}}, r::FloatRange) = + FloatRange{T}(r.start,r.step,r.len,r.divisor) -function -(r1::OrdinalRange, r2::OrdinalRange) - r1l = length(r1) - r1l == length(r2) || error("argument dimensions must match") - range(r1.start-r2.start, step(r1)-step(r2), r1l) -end +promote_rule{F,OR<:OrdinalRange}(::Type{FloatRange{F}}, ::Type{OR}) = + FloatRange{promote_type(F,eltype(OR))} +convert{T}(::Type{FloatRange{T}}, r::OrdinalRange) = + FloatRange{T}(start(r), step(r), length(r), one(T)) + +# +/- of ranges is defined in operators.jl (to be able to use @eval etc.) ## non-linear operations on ranges ## diff --git a/test/ranges.jl b/test/ranges.jl index 8379eaab90218..74afc963e1398 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -283,3 +283,12 @@ end # issue #6364 @test length((1:64)*(pi/5)) == 64 + +# issue #6973 +let r1 = 1.0:0.1:2.0, r2 = 1.0f0:0.2f0:3.0f0, r3 = 1:2:21 + @test r1 + r1 == 2*r1 + @test r1 + r2 == 2.0:0.3:5.0 + @test (r1 + r2) - r2 == r1 + @test r1 + r3 == convert(FloatRange{Float64}, r3) + r1 + @test r3 + r3 == 2 * r3 +end From 206881eeed7455f987572bb7ce6c1dcf73054837 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 27 May 2014 17:04:03 -0400 Subject: [PATCH 2/2] fix FloatRange{T}+FloatRange{T} definition --- base/operators.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/operators.jl b/base/operators.jl index 1c1b3a7cd9d80..733b326e116c2 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -322,7 +322,7 @@ for f in (:+, :-) range($f(r1.start,r2.start), $f(step(r1),step(r2)), r1l) end - function $f{T}(r1::FloatRange{T}, r2::FloatRange{T}) + function $f{T<:FloatingPoint}(r1::FloatRange{T}, r2::FloatRange{T}) len = r1.len len == r2.len || error("argument dimensions must match") divisor1, divisor2 = r1.divisor, r2.divisor