Skip to content

Commit 32d0645

Browse files
authored
Merge pull request #18777 from JuliaLang/teh/linspace
Make LinSpace generic
2 parents 4976485 + a12e587 commit 32d0645

17 files changed

+928
-393
lines changed

NEWS.md

+28
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,33 @@ This section lists changes that do not have deprecation warnings.
130130
(since it is shorthand for `NTuple{N,T} where T`). To get the old behavior of matching
131131
any tuple, use `NTuple{N,Any}` ([#18457]).
132132

133+
* `FloatRange` has been replaced by `StepRangeLen`, and the internal
134+
representation of `LinSpace` has changed. Aside from changes in
135+
the internal field names, this leads to several differences in
136+
behavior ([#18777]):
137+
138+
+ Both `StepRangeLen` and `LinSpace` can represent ranges of
139+
arbitrary object types---they are no longer limited to
140+
floating-point numbers.
141+
142+
+ For ranges that produce `Float64`, `Float32`, or `Float16`
143+
numbers, `StepRangeLen` can be used to produce values with
144+
little or no roundoff error due to internal arithmetic that is
145+
typically twice the precision of the output result.
146+
147+
+ To take advantage of this precision, `linspace(start, stop,
148+
len)` now returns a range of type `StepRangeLen` rather than
149+
`LinSpace` when `start` and `stop` are
150+
`FloatNN`. `LinSpace(start, stop, len)` always returns a
151+
`LinSpace`.
152+
153+
+ `StepRangeLen(a, step, len)` constructs an ordinary-precision range
154+
using the values and types of `a` and `step` as given, whereas
155+
`range(a, step, len)` will attempt to match inputs `a::FloatNN`
156+
and `step::FloatNN` to rationals and construct a `StepRangeLen`
157+
that internally uses twice-precision arithmetic. These two
158+
outcomes exhibit differences in both precision and speed.
159+
133160
Library improvements
134161
--------------------
135162

@@ -891,6 +918,7 @@ Language tooling improvements
891918
[#18628]: https://github.com/JuliaLang/julia/issues/18628
892919
[#18644]: https://github.com/JuliaLang/julia/issues/18644
893920
[#18690]: https://github.com/JuliaLang/julia/issues/18690
921+
[#18777]: https://github.com/JuliaLang/julia/issues/18777
894922
[#18839]: https://github.com/JuliaLang/julia/issues/18839
895923
[#18931]: https://github.com/JuliaLang/julia/issues/18931
896924
[#18965]: https://github.com/JuliaLang/julia/issues/18965

base/abstractarray.jl

+2-4
Original file line numberDiff line numberDiff line change
@@ -781,11 +781,9 @@ full(x::AbstractArray) = x
781781

782782
map{T<:Real}(::Type{T}, r::StepRange) = T(r.start):T(r.step):T(last(r))
783783
map{T<:Real}(::Type{T}, r::UnitRange) = T(r.start):T(last(r))
784-
map{T<:AbstractFloat}(::Type{T}, r::FloatRange) = FloatRange(T(r.start), T(r.step), r.len, T(r.divisor))
784+
map{T<:AbstractFloat}(::Type{T}, r::StepRangeLen) = convert(StepRangeLen{T}, r)
785785
function map{T<:AbstractFloat}(::Type{T}, r::LinSpace)
786-
new_len = T(r.len)
787-
new_len == r.len || error("$r: too long for $T")
788-
LinSpace(T(r.start), T(r.stop), new_len, T(r.divisor))
786+
LinSpace(T(r.start), T(r.stop), length(r))
789787
end
790788

791789
## unsafe/pointer conversions ##

base/coreimg.jl

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ include("options.jl")
2323
# core operations & types
2424
include("promotion.jl")
2525
include("tuple.jl")
26+
include("traits.jl")
2627
include("range.jl")
2728
include("expr.jl")
2829
include("error.jl")

base/dates/types.jl

+3
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,6 @@ import Base: sleep, Timer, timedwait
310310
sleep(time::Period) = sleep(toms(time) / 1000)
311311
Timer(time::Period, repeat::Period=Second(0)) = Timer(toms(time) / 1000, toms(repeat) / 1000)
312312
timedwait(testcb::Function, time::Period) = timedwait(testcb, toms(time) / 1000)
313+
314+
(::Type{Base.TypeOrder}){T<:AbstractTime}(::Type{T}) = Base.HasOrder()
315+
(::Type{Base.TypeArithmetic}){T<:AbstractTime}(::Type{T}) = Base.ArithmeticOverflows()

base/deprecated.jl

+5-1
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,7 @@ end
14711471
# Deprecate manually vectorized `big` methods in favor of compact broadcast syntax
14721472
@deprecate big(r::UnitRange) big.(r)
14731473
@deprecate big(r::StepRange) big.(r)
1474-
@deprecate big(r::FloatRange) big.(r)
1474+
@deprecate big(r::StepRangeLen) big.(r)
14751475
@deprecate big(r::LinSpace) big.(r)
14761476
@deprecate big{T<:Integer,N}(x::AbstractArray{T,N}) big.(x)
14771477
@deprecate big{T<:AbstractFloat,N}(x::AbstractArray{T,N}) big.(x)
@@ -1842,4 +1842,8 @@ eval(Dates, quote
18421842
end
18431843
end)
18441844

1845+
# FloatRange replaced by StepRangeLen
1846+
1847+
@deprecate FloatRange{T}(start::T, step, len, den) Base.floatrange(T, start, step, len, den)
1848+
18451849
# End deprecations scheduled for 0.6

base/exports.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export
6262
ExponentialBackOff,
6363
Factorization,
6464
FileMonitor,
65-
FloatRange,
65+
StepRangeLen,
6666
Future,
6767
Hermitian,
6868
UniformScaling,

base/float.jl

+30-14
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,29 @@ fpinttype(::Type{Float16}) = UInt16
752752
# maximum float exponent without bias
753753
@pure exponent_raw_max{T<:AbstractFloat}(::Type{T}) = Int(exponent_mask(T) >> significand_bits(T))
754754

755+
## TwicePrecision utilities
756+
# The numeric constants are half the number of bits in the mantissa
757+
for (F, T, n) in ((Float16, UInt16, 5), (Float32, UInt32, 12), (Float64, UInt64, 26))
758+
@eval begin
759+
function truncbits(x::$F, nb)
760+
@_inline_meta
761+
truncmask(x, typemax($T) << nb)
762+
end
763+
function truncmask(x::$F, mask)
764+
@_inline_meta
765+
reinterpret($F, mask & reinterpret($T, x))
766+
end
767+
function splitprec(x::$F)
768+
@_inline_meta
769+
hi = truncmask(x, typemax($T) << $n)
770+
hi, x-hi
771+
end
772+
end
773+
end
774+
775+
truncbits(x, nb) = x
776+
truncmask(x, mask) = x
777+
755778
## Array operations on floating point numbers ##
756779

757780
float{T<:AbstractFloat}(A::AbstractArray{T}) = A
@@ -763,26 +786,19 @@ function float{T}(A::AbstractArray{T})
763786
convert(AbstractArray{typeof(float(zero(T)))}, A)
764787
end
765788

766-
for fn in (:float,)
767-
@eval begin
768-
$fn(r::StepRange) = $fn(r.start):$fn(r.step):$fn(last(r))
769-
$fn(r::UnitRange) = $fn(r.start):$fn(last(r))
770-
$fn(r::FloatRange) = FloatRange($fn(r.start), $fn(r.step), r.len, $fn(r.divisor))
771-
function $fn(r::LinSpace)
772-
new_len = $fn(r.len)
773-
new_len == r.len || error(string(r, ": too long for ", $fn))
774-
LinSpace($fn(r.start), $fn(r.stop), new_len, $fn(r.divisor))
775-
end
776-
end
789+
float(r::StepRange) = float(r.start):float(r.step):float(last(r))
790+
float(r::UnitRange) = float(r.start):float(last(r))
791+
float(r::StepRangeLen) = StepRangeLen(float(r.ref), float(r.step), length(r), r.offset)
792+
function float(r::LinSpace)
793+
LinSpace(float(r.start), float(r.stop), length(r))
777794
end
778795

779796
# big, broadcast over arrays
780797
# TODO: do the definitions below primarily pertaining to integers belong in float.jl?
781798
function big end # no prior definitions of big in sysimg.jl, necessitating this
782799
broadcast(::typeof(big), r::UnitRange) = big(r.start):big(last(r))
783800
broadcast(::typeof(big), r::StepRange) = big(r.start):big(r.step):big(last(r))
784-
broadcast(::typeof(big), r::FloatRange) = FloatRange(big(r.start), big(r.step), r.len, big(r.divisor))
801+
broadcast(::typeof(big), r::StepRangeLen) = StepRangeLen(big(r.ref), big(r.step), length(r), r.offset)
785802
function broadcast(::typeof(big), r::LinSpace)
786-
big(r.len) == r.len || throw(ArgumentError(string(r, ": too long for ", big)))
787-
LinSpace(big(r.start), big(r.stop), big(r.len), big(r.divisor))
803+
LinSpace(big(r.start), big(r.stop), length(r))
788804
end

base/mpfr.jl

+5
Original file line numberDiff line numberDiff line change
@@ -978,4 +978,9 @@ function Base.deepcopy_internal(x::BigFloat, stackdict::ObjectIdDict)
978978
return y
979979
end
980980

981+
function lerpi(j::Integer, d::Integer, a::BigFloat, b::BigFloat)
982+
t = BigFloat(j)/d
983+
fma(t, b, fma(-t, a, a))
984+
end
985+
981986
end #module

base/operators.jl

+14-30
Original file line numberDiff line numberDiff line change
@@ -976,45 +976,29 @@ for f in (:+, :-)
976976
range($f(first(r1),first(r2)), $f(step(r1),step(r2)), r1l)
977977
end
978978

979-
function $f{T<:AbstractFloat}(r1::FloatRange{T}, r2::FloatRange{T})
979+
function $f{T}(r1::LinSpace{T}, r2::LinSpace{T})
980980
len = r1.len
981981
(len == r2.len ||
982982
throw(DimensionMismatch("argument dimensions must match")))
983-
divisor1, divisor2 = r1.divisor, r2.divisor
984-
if divisor1 == divisor2
985-
FloatRange{T}($f(r1.start,r2.start), $f(r1.step,r2.step),
986-
len, divisor1)
987-
else
988-
d1 = Int(divisor1)
989-
d2 = Int(divisor2)
990-
d = lcm(d1,d2)
991-
s1 = div(d,d1)
992-
s2 = div(d,d2)
993-
FloatRange{T}($f(r1.start*s1, r2.start*s2),
994-
$f(r1.step*s1, r2.step*s2), len, d)
995-
end
996-
end
997-
998-
function $f{T<:AbstractFloat}(r1::LinSpace{T}, r2::LinSpace{T})
999-
len = r1.len
1000-
(len == r2.len ||
1001-
throw(DimensionMismatch("argument dimensions must match")))
1002-
divisor1, divisor2 = r1.divisor, r2.divisor
1003-
if divisor1 == divisor2
1004-
LinSpace{T}($f(r1.start, r2.start), $f(r1.stop, r2.stop),
1005-
len, divisor1)
1006-
else
1007-
linspace(convert(T, $f(first(r1), first(r2))),
1008-
convert(T, $f(last(r1), last(r2))), len)
1009-
end
983+
linspace(convert(T, $f(first(r1), first(r2))),
984+
convert(T, $f(last(r1), last(r2))), len)
1010985
end
1011986

1012-
$f(r1::Union{FloatRange, OrdinalRange, LinSpace},
1013-
r2::Union{FloatRange, OrdinalRange, LinSpace}) =
987+
$f(r1::Union{StepRangeLen, OrdinalRange, LinSpace},
988+
r2::Union{StepRangeLen, OrdinalRange, LinSpace}) =
1014989
$f(promote_noncircular(r1, r2)...)
1015990
end
1016991
end
1017992

993+
function +{T,S}(r1::StepRangeLen{T,S}, r2::StepRangeLen{T,S})
994+
len = length(r1)
995+
(len == length(r2) ||
996+
throw(DimensionMismatch("argument dimensions must match")))
997+
StepRangeLen(first(r1)+first(r2), step(r1)+step(r2), len)
998+
end
999+
1000+
-(r1::StepRangeLen, r2::StepRangeLen) = +(r1, -r2)
1001+
10181002
# Pair
10191003

10201004
immutable Pair{A,B}

0 commit comments

Comments
 (0)