Skip to content

Commit 59cdac6

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

File tree

5 files changed

+59
-13
lines changed

5 files changed

+59
-13
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

+24-7
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ function linspace{T<:FloatingPoint}(start::T, stop::T, len::T)
207207
s = convert(T,n*e)
208208
if isinf(a*n) || isinf(c*n)
209209
s, p = frexp(s)
210-
p = oftype(s,2)^p
211-
a /= p; c /= p
210+
p2 = oftype(s,2)^p
211+
a /= p2; c /= p2
212212
end
213213
if a*n/s == start && c*n/s == stop
214214
return LinSpace(a, c, len, s)
@@ -218,8 +218,8 @@ function linspace{T<:FloatingPoint}(start::T, stop::T, len::T)
218218
a, c, s = start, stop, n
219219
if isinf(a*n) || isinf(c*n)
220220
s, p = frexp(s)
221-
p = oftype(s,2)^p
222-
a /= p; c /= p
221+
p2 = oftype(s,2)^p
222+
a /= p2; c /= p2
223223
end
224224
if a*n/s == start && c*n/s == stop
225225
return LinSpace(a, c, len, s)
@@ -546,17 +546,26 @@ end
546546
.+(x::Real, r::Range) = (x+first(r)):step(r):(x+last(r))
547547
#.+(x::Real, r::StepRange) = range(x + r.start, r.step, length(r))
548548
.+(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)
549+
function .+(x::Real, r::LinSpace)
550+
x2 = ifelse(r.len == 0, x, x * r.divisor / (r.len - 1))
551+
LinSpace(x2 + r.start, x2 + r.stop, r.len, r.divisor)
552+
end
550553
.+(r::Range, x::Real) = x + r
551554
#.+(r::FloatRange, x::Real) = x + r
552555

553556
.-(x::Real, r::Range) = (x-first(r)):-step(r):(x-last(r))
554557
.-(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)
558+
function .-(x::Real, r::LinSpace)
559+
x2 = ifelse(r.len == 0, x, x * r.divisor / (r.len - 1))
560+
LinSpace(x2 - r.start, x2 - r.stop, r.len, r.divisor)
561+
end
556562
.-(r::UnitRange, x::Real) = range(r.start-x, length(r))
557563
.-(r::StepRange , x::Real) = range(r.start-x, r.step, length(r))
558564
.-(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)
565+
function .-(r::LinSpace, x::Real)
566+
x2 = ifelse(r.len == 0, x, x * r.divisor / (r.len - 1))
567+
LinSpace(r.start - x2, r.stop - x2, r.len, r.divisor)
568+
end
560569

561570
.*(x::Real, r::OrdinalRange) = range(x*r.start, x*step(r), length(r))
562571
.*(x::Real, r::FloatRange) = FloatRange(x*r.start, x*r.step, r.len, r.divisor)
@@ -611,6 +620,14 @@ convert{T}(::Type{LinSpace{T}}, r::OrdinalRange) =
611620
convert{T}(::Type{LinSpace}, r::OrdinalRange{T}) =
612621
convert(LinSpace{typeof(float(first(r)))}, r)
613622

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

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

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)