Skip to content

Commit 4921ae2

Browse files
committed
Fix plus and minus for LinSpace, and other missing methods. Close #12195
1 parent 25ec6ba commit 4921ae2

File tree

5 files changed

+56
-9
lines changed

5 files changed

+56
-9
lines changed

base/abstractarray.jl

+5
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ map(::Type{Unsigned}, a::Array) = map!(Unsigned, similar(a,typeof(Unsigned(one(e
427427
map{T<:Real}(::Type{T}, r::StepRange) = T(r.start):T(r.step):T(last(r))
428428
map{T<:Real}(::Type{T}, r::UnitRange) = T(r.start):T(last(r))
429429
map{T<:FloatingPoint}(::Type{T}, r::FloatRange) = FloatRange(T(r.start), T(r.step), r.len, T(r.divisor))
430+
function map{T<:FloatingPoint}(::Type{T}, r::LinSpace)
431+
new_len = T(r.len)
432+
new_len == r.len || error("$r: too long for $T")
433+
LinSpace(T(r.start), T(r.stop), new_len, T(r.divisor))
434+
end
430435

431436
## unsafe/pointer conversions ##
432437

base/float.jl

+5
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@ for fn in (:float,:big)
469469
$fn(r::StepRange) = $fn(r.start):$fn(r.step):$fn(last(r))
470470
$fn(r::UnitRange) = $fn(r.start):$fn(last(r))
471471
$fn(r::FloatRange) = FloatRange($fn(r.start), $fn(r.step), r.len, $fn(r.divisor))
472+
function $fn(r::LinSpace)
473+
new_len = $fn(r.len)
474+
new_len == r.len || error(string(r, ": too long for ", $fn))
475+
LinSpace($fn(r.start), $fn(r.stop), new_len, $fn(r.divisor))
476+
end
472477
end
473478
end
474479

base/operators.jl

+21-5
Original file line numberDiff line numberDiff line change
@@ -327,13 +327,15 @@ for f in (:+, :-)
327327
@eval begin
328328
function $f(r1::OrdinalRange, r2::OrdinalRange)
329329
r1l = length(r1)
330-
r1l == length(r2) || error("argument dimensions must match")
330+
(r1l == length(r2) ||
331+
throw(DimensionMismatch("argument dimensions must match")))
331332
range($f(r1.start,r2.start), $f(step(r1),step(r2)), r1l)
332333
end
333334

334335
function $f{T<:FloatingPoint}(r1::FloatRange{T}, r2::FloatRange{T})
335336
len = r1.len
336-
len == r2.len || error("argument dimensions must match")
337+
(len == r2.len ||
338+
throw(DimensionMismatch("argument dimensions must match")))
337339
divisor1, divisor2 = r1.divisor, r2.divisor
338340
if divisor1 == divisor2
339341
FloatRange{T}($f(r1.start,r2.start), $f(r1.step,r2.step),
@@ -349,9 +351,23 @@ for f in (:+, :-)
349351
end
350352
end
351353

352-
$f(r1::FloatRange, r2::FloatRange) = $f(promote(r1,r2)...)
353-
$f(r1::FloatRange, r2::OrdinalRange) = $f(promote(r1,r2)...)
354-
$f(r1::OrdinalRange, r2::FloatRange) = $f(promote(r1,r2)...)
354+
function $f{T<:FloatingPoint}(r1::LinSpace{T}, r2::LinSpace{T})
355+
len = r1.len
356+
(len == r2.len ||
357+
throw(DimensionMismatch("argument dimensions must match")))
358+
divisor1, divisor2 = r1.divisor, r2.divisor
359+
if divisor1 == divisor2
360+
LinSpace{T}($f(r1.start, r2.start), $f(r1.stop, r2.stop),
361+
len, divisor1)
362+
else
363+
linspace(convert(T, $f(first(r1), first(r2))),
364+
convert(T, $f(last(r1), last(r2))), len)
365+
end
366+
end
367+
368+
$f(r1::Union{FloatRange, OrdinalRange, LinSpace},
369+
r2::Union{FloatRange, OrdinalRange, LinSpace}) =
370+
$f(promote(r1, r2)...)
355371
end
356372
end
357373

base/range.jl

+21-3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ function linspace{T<:FloatingPoint}(start::T, stop::T, len::T)
197197
len - n == 1 || error("linspace($start, $stop, $len): too long for $T")
198198
a0, b = rat(start)
199199
a = convert(T,a0)
200+
p::T
200201
if a/convert(T,b) == start
201202
c0, d = rat(stop)
202203
c = convert(T,c0)
@@ -546,17 +547,26 @@ end
546547
.+(x::Real, r::Range) = (x+first(r)):step(r):(x+last(r))
547548
#.+(x::Real, r::StepRange) = range(x + r.start, r.step, length(r))
548549
.+(x::Real, r::FloatRange) = FloatRange(r.divisor*x + r.start, r.step, r.len, r.divisor)
549-
.+(x::Real, r::LinSpace) = LinSpace(x + r.start, x + r.stop, r.len, r.divisor)
550+
function .+(x::Real, r::LinSpace)
551+
x2 = ifelse(r.len == 0, x, x * r.divisor / (r.len - 1))
552+
LinSpace(x2 + r.start, x2 + r.stop, r.len, r.divisor)
553+
end
550554
.+(r::Range, x::Real) = x + r
551555
#.+(r::FloatRange, x::Real) = x + r
552556

553557
.-(x::Real, r::Range) = (x-first(r)):-step(r):(x-last(r))
554558
.-(x::Real, r::FloatRange) = FloatRange(r.divisor*x - r.start, -r.step, r.len, r.divisor)
555-
.-(x::Real, r::LinSpace) = LinSpace(x - r.start, x - r.stop, r.len, r.divisor)
559+
function .-(x::Real, r::LinSpace)
560+
x2 = ifelse(r.len == 0, x, x * r.divisor / (r.len - 1))
561+
LinSpace(x2 - r.start, x2 - r.stop, r.len, r.divisor)
562+
end
556563
.-(r::UnitRange, x::Real) = range(r.start-x, length(r))
557564
.-(r::StepRange , x::Real) = range(r.start-x, r.step, length(r))
558565
.-(r::FloatRange, x::Real) = FloatRange(r.start - r.divisor*x, r.step, r.len, r.divisor)
559-
.-(r::LinSpace, x::Real) = LinSpace(r.start - x, r.stop - x, r.len, r.divisor)
566+
function .-(r::LinSpace, x::Real)
567+
x2 = ifelse(r.len == 0, x, x * r.divisor / (r.len - 1))
568+
LinSpace(r.start - x2, r.stop - x2, r.len, r.divisor)
569+
end
560570

561571
.*(x::Real, r::OrdinalRange) = range(x*r.start, x*step(r), length(r))
562572
.*(x::Real, r::FloatRange) = FloatRange(x*r.start, x*r.step, r.len, r.divisor)
@@ -611,6 +621,14 @@ convert{T}(::Type{LinSpace{T}}, r::OrdinalRange) =
611621
convert{T}(::Type{LinSpace}, r::OrdinalRange{T}) =
612622
convert(LinSpace{typeof(float(first(r)))}, r)
613623

624+
# Promote FloatRange to LinSpace
625+
promote_rule{F,OR<:FloatRange}(::Type{LinSpace{F}}, ::Type{OR}) =
626+
LinSpace{promote_type(F,eltype(OR))}
627+
convert{T}(::Type{LinSpace{T}}, r::FloatRange) =
628+
linspace(convert(T, first(r)), convert(T, last(r)), convert(T, length(r)))
629+
convert{T}(::Type{LinSpace}, r::FloatRange{T}) =
630+
convert(LinSpace{T}, r)
631+
614632

615633
# +/- of ranges is defined in operators.jl (to be able to use @eval etc.)
616634

test/ranges.jl

+4-1
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,11 @@ end
245245
@test all(((1:5) - [1:5;]) .== 0)
246246

247247
# exercise fallback addition of ranges
248-
@test ((linspace(1.,5.,5) - linspace(1.,5.,5)) == zeros(5))
248+
@test ((linspace(1.,5.,5) - linspace(1.,5.,5)) == linspace(0, 0, 5))
249+
@test_throws DimensionMismatch (linspace(1.,5.,5) + linspace(1.,5.,6))
249250
@test_throws DimensionMismatch (linspace(1.,5.,5) - linspace(1.,5.,6))
251+
@test_throws DimensionMismatch (linspace(1.,5.,5) .* linspace(1.,5.,6))
252+
@test_throws DimensionMismatch (linspace(1.,5.,5) ./ linspace(1.,5.,6))
250253

251254
# tricky floating-point ranges
252255

0 commit comments

Comments
 (0)