@@ -308,23 +308,57 @@ end
308308
309309# # StepRangeLen
310310
311- # If using TwicePrecision numbers, deliberately force user to specify offset
312- StepRangeLen (ref:: TwicePrecision{T} , step:: TwicePrecision{T} , len:: Integer , offset:: Integer ) where {T} =
311+ # Use TwicePrecision only for Float64; use Float64 for T<:Union{Float16,Float32}
312+ # Ratio-of-integers constructors
313+ function steprangelen_hp (:: Type{Float64} , ref:: Tuple{Integer,Integer} ,
314+ step:: Tuple{Integer,Integer} , nb:: Integer ,
315+ len:: Integer , offset:: Integer )
316+ StepRangeLen (TwicePrecision {Float64} (ref),
317+ TwicePrecision {Float64} (step, nb), Int (len), offset)
318+ end
319+
320+ function steprangelen_hp (:: Type{T} , ref:: Tuple{Integer,Integer} ,
321+ step:: Tuple{Integer,Integer} , nb:: Integer ,
322+ len:: Integer , offset:: Integer ) where {T<: IEEEFloat }
323+ StepRangeLen {T} (ref[1 ]/ ref[2 ], step[1 ]/ step[2 ], Int (len), offset)
324+ end
325+
326+ # AbstractFloat constructors (can supply a single number or a 2-tuple
327+ const F_or_FF = Union{AbstractFloat, Tuple{AbstractFloat,AbstractFloat}}
328+ asF64 (x:: AbstractFloat ) = Float64 (x)
329+ asF64 (x:: Tuple{AbstractFloat,AbstractFloat} ) = Float64 (x[1 ]) + Float64 (x[2 ])
330+
331+ function steprangelen_hp (:: Type{Float64} , ref:: F_or_FF ,
332+ step:: F_or_FF , nb:: Integer ,
333+ len:: Integer , offset:: Integer )
334+ StepRangeLen (TwicePrecision {Float64} (ref... ),
335+ twiceprecision (TwicePrecision {Float64} (step... ), nb), Int (len), offset)
336+ end
337+
338+ function steprangelen_hp (:: Type{T} , ref:: F_or_FF ,
339+ step:: F_or_FF , nb:: Integer ,
340+ len:: Integer , offset:: Integer ) where {T<: IEEEFloat }
341+ StepRangeLen {T} (asF64 (ref),
342+ asF64 (step), Int (len), offset)
343+ end
344+
345+
346+
347+ StepRangeLen (ref:: TwicePrecision{T} , step:: TwicePrecision{T} ,
348+ len:: Integer , offset:: Integer = 1 ) where {T} =
313349 StepRangeLen {T,TwicePrecision{T},TwicePrecision{T}} (ref, step, len, offset)
314350
315351# Construct range for rational start=start_n/den, step=step_n/den
316352function floatrange (:: Type{T} , start_n:: Integer , step_n:: Integer , len:: Integer , den:: Integer ) where T
317353 if len < 2
318- return StepRangeLen (TwicePrecision {T} ((start_n, den)),
319- TwicePrecision {T} ((step_n, den)), Int (len), 1 )
354+ return steprangelen_hp (T, (start_n, den), (step_n, den), 0 , Int (len), 1 )
320355 end
321356 # index of smallest-magnitude value
322357 imin = clamp (round (Int, - start_n/ step_n+ 1 ), 1 , Int (len))
323358 # Compute smallest-magnitude element to 2x precision
324359 ref_n = start_n+ (imin- 1 )* step_n # this shouldn't overflow, so don't check
325360 nb = nbitslen (T, len, imin)
326- StepRangeLen (TwicePrecision {T} ((ref_n, den)),
327- TwicePrecision {T} ((step_n, den), nb), Int (len), imin)
361+ steprangelen_hp (T, (ref_n, den), (step_n, den), nb, Int (len), imin)
328362end
329363
330364function floatrange (a:: AbstractFloat , st:: AbstractFloat , len:: Real , divisor:: AbstractFloat )
@@ -339,8 +373,7 @@ function floatrange(a::AbstractFloat, st::AbstractFloat, len::Real, divisor::Abs
339373 end
340374 # Fallback (misses the opportunity to set offset different from 1,
341375 # but otherwise this is still high-precision)
342- StepRangeLen (TwicePrecision {T} ((a,divisor)),
343- TwicePrecision {T} ((st,divisor), nbitslen (T, len, 1 )), Int (len), 1 )
376+ steprangelen_hp (T, (a,divisor), (st,divisor), nbitslen (T, len, 1 ), Int (len), 1 )
344377end
345378
346379function colon (start:: T , step:: T , stop:: T ) where T<: Union{Float16,Float32,Float64}
@@ -381,8 +414,7 @@ function colon(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float6
381414 # if we've overshot the end, subtract one:
382415 len -= (start < stop < stop′) + (start > stop > stop′)
383416 end
384-
385- StepRangeLen (TwicePrecision (start, zero (T)), twiceprecision (step, nbitslen (T, len, 1 )), len)
417+ steprangelen_hp (T, start, step, 0 , len, 1 )
386418end
387419
388420function range (a:: T , st:: T , len:: Integer ) where T<: Union{Float16,Float32,Float64}
@@ -399,16 +431,7 @@ function range(a::T, st::T, len::Integer) where T<:Union{Float16,Float32,Float64
399431 return floatrange (T, start_n, step_n, len, den)
400432 end
401433 end
402- StepRangeLen (TwicePrecision (a, zero (T)), TwicePrecision (st, zero (T)), len)
403- end
404-
405- step (r:: StepRangeLen{T,R,S} ) where {T,R,S<: TwicePrecision } = convert (eltype (S), r. step)
406-
407- start (r:: StepRangeLen{<:Any,<:TwicePrecision,<:TwicePrecision} ) = 1
408- done (r:: StepRangeLen{<:Any,<:TwicePrecision,<:TwicePrecision} , i:: Int ) = length (r) < i
409- function next (r:: StepRangeLen{<:Any,<:TwicePrecision,<:TwicePrecision} , i:: Int )
410- @_inline_meta
411- unsafe_getindex (r, i), i+ 1
434+ steprangelen_hp (T, a, st, 0 , len, 1 )
412435end
413436
414437# This assumes that r.step has already been split so that (0:len-1)*r.step.hi is exact
542565function linspace (start:: T , stop:: T , len:: Integer ) where {T<: IEEEFloat }
543566 len < 2 && return _linspace1 (T, start, stop, len)
544567 if start == stop
545- return StepRangeLen ( TwicePrecision (start, zero (T)), TwicePrecision ( zero (T), zero (T)), len)
568+ return steprangelen_hp (T, start, zero (T), 0 , len, 1 )
546569 end
547570 # Attempt to find exact rational approximations
548571 start_n, start_d = rat (start)
@@ -587,8 +610,7 @@ function _linspace(start::T, stop::T, len::Integer) where {T<:IEEEFloat}
587610 if len == 2 && ! isfinite (step)
588611 # For very large endpoints where step overflows, exploit the
589612 # split-representation to handle the overflow
590- return StepRangeLen (TwicePrecision (start, zero (T)),
591- TwicePrecision (- start, stop), 2 )
613+ return steprangelen_hp (T, start, (- start, stop), 0 , 2 , 1 )
592614 end
593615 # 2x calculations to get high precision endpoint matching while also
594616 # preventing overflow in ref_hi+(i-offset)*step_hi
@@ -601,23 +623,22 @@ function _linspace(start::T, stop::T, len::Integer) where {T<:IEEEFloat}
601623 a, b = (start - x1_hi) - x1_lo, (stop - x2_hi) - x2_lo
602624 step_lo = (b - a)/ (len - 1 )
603625 ref_lo = a - (1 - imin)* step_lo
604- StepRangeLen ( TwicePrecision (ref, ref_lo), TwicePrecision (step_hi, step_lo), Int (len), imin)
626+ steprangelen_hp (T, (ref, ref_lo), (step_hi, step_lo), 0 , Int (len), imin)
605627end
606628
607629# linspace for rational numbers, start = start_n/den, stop = stop_n/den
608630# Note this returns a StepRangeLen
609631function linspace (:: Type{T} , start_n:: Integer , stop_n:: Integer , len:: Integer , den:: Integer ) where T
610632 len < 2 && return _linspace1 (T, start_n/ den, stop_n/ den, len)
611- start_n == stop_n && return StepRangeLen ( TwicePrecision {T} (( start_n, den)), zero (TwicePrecision{T}) , len)
633+ start_n == stop_n && return steprangelen_hp (T, ( start_n, den), ( zero (start_n), den), 0 , len)
612634 tmin = - start_n/ (Float64 (stop_n) - Float64 (start_n))
613635 imin = round (Int, tmin* (len- 1 )+ 1 )
614636 imin = clamp (imin, 1 , Int (len))
615637 ref_num = Int128 (len- imin) * start_n + Int128 (imin- 1 ) * stop_n
616638 ref_denom = Int128 (len- 1 ) * den
617- ref = TwicePrecision {T} ((ref_num, ref_denom))
618- step_full = TwicePrecision {T} ((Int128 (stop_n) - Int128 (start_n), ref_denom))
619- step = twiceprecision (step_full, nbitslen (T, len, imin))
620- StepRangeLen (ref, step, Int (len), imin)
639+ ref = (ref_num, ref_denom)
640+ step_full = (Int128 (stop_n) - Int128 (start_n), ref_denom)
641+ steprangelen_hp (T, ref, step_full, nbitslen (T, len, imin), Int (len), imin)
621642end
622643
623644# For len < 2
0 commit comments