Skip to content

Commit f1f0ef6

Browse files
committed
add +/- for FloatRange (fix #6973)
1 parent eb464f0 commit f1f0ef6

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

base/operators.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,39 @@ to_index(I::(Any,Any,Any,Any)) = (to_index(I[1]), to_index(I[2]), to_index(I[3])
313313
to_index(I::Tuple) = map(to_index, I)
314314
to_index(i) = error("invalid index: $i")
315315

316+
# Addition/subtraction of ranges
317+
for f in (:+, :-)
318+
@eval begin
319+
function $f(r1::OrdinalRange, r2::OrdinalRange)
320+
r1l = length(r1)
321+
r1l == length(r2) || error("argument dimensions must match")
322+
range($f(r1.start,r2.start), $f(step(r1),step(r2)), r1l)
323+
end
324+
325+
function $f{T}(r1::FloatRange{T}, r2::FloatRange{T})
326+
len = r1.len
327+
len == r2.len || error("argument dimensions must match")
328+
divisor1, divisor2 = r1.divisor, r2.divisor
329+
if divisor1 == divisor2
330+
FloatRange{T}($f(r1.start,r2.start), $f(r1.step,r2.step),
331+
len, divisor1)
332+
else
333+
d1 = int(divisor1)
334+
d2 = int(divisor2)
335+
d = lcm(d1,d2)
336+
s1 = div(d,d1)
337+
s2 = div(d,d2)
338+
FloatRange{T}($f(r1.start*s1, r2.start*s2),
339+
$f(r1.step*s1, r2.step*s2), len, d)
340+
end
341+
end
342+
343+
$f(r1::FloatRange, r2::FloatRange) = $f(promote(r1,r2)...)
344+
$f(r1::FloatRange, r2::OrdinalRange) = $f(promote(r1,r2)...)
345+
$f(r1::OrdinalRange, r2::FloatRange) = $f(promote(r1,r2)...)
346+
end
347+
end
348+
316349
# vectorization
317350

318351
macro vectorize_1arg(S,f)

base/range.jl

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -437,18 +437,17 @@ end
437437
./(r::OrdinalRange, x::Real) = range(r.start/x, step(r)/x, length(r))
438438
./(r::FloatRange, x::Real) = FloatRange(r.start/x, r.step/x, r.len, r.divisor)
439439

440-
# TODO: better implementations for FloatRanges?
441-
function +(r1::OrdinalRange, r2::OrdinalRange)
442-
r1l = length(r1)
443-
r1l == length(r2) || error("argument dimensions must match")
444-
range(r1.start+r2.start, step(r1)+step(r2), r1l)
445-
end
440+
promote_rule{T1,T2}(::Type{FloatRange{T1}},::Type{FloatRange{T2}}) =
441+
FloatRange{promote_type(T1,T2)}
442+
convert{T}(::Type{FloatRange{T}}, r::FloatRange) =
443+
FloatRange{T}(r.start,r.step,r.len,r.divisor)
446444

447-
function -(r1::OrdinalRange, r2::OrdinalRange)
448-
r1l = length(r1)
449-
r1l == length(r2) || error("argument dimensions must match")
450-
range(r1.start-r2.start, step(r1)-step(r2), r1l)
451-
end
445+
promote_rule{F,OR<:OrdinalRange}(::Type{FloatRange{F}}, ::Type{OR}) =
446+
FloatRange{promote_type(F,eltype(OR))}
447+
convert{T}(::Type{FloatRange{T}}, r::OrdinalRange) =
448+
FloatRange{T}(start(r), step(r), length(r), one(T))
449+
450+
# +/- of ranges is defined in operators.jl (to be able to use @eval etc.)
452451

453452
## non-linear operations on ranges ##
454453

test/ranges.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,12 @@ end
283283

284284
# issue #6364
285285
@test length((1:64)*(pi/5)) == 64
286+
287+
# issue #6973
288+
let r1 = 1.0:0.1:2.0, r2 = 1.0f0:0.2f0:3.0f0, r3 = 1:2:21
289+
@test r1 + r1 == 2*r1
290+
@test r1 + r2 == 2.0:0.3:5.0
291+
@test (r1 + r2) - r2 == r1
292+
@test r1 + r3 == convert(FloatRange{Float64}, r3) + r1
293+
@test r3 + r3 == 2 * r3
294+
end

0 commit comments

Comments
 (0)