diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 80d1917ea599f..23cc2690f5b44 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -122,8 +122,6 @@ end function colon{T<:Union{Float16,Float32,Float64}}(start::T, step::T, stop::T) step == 0 && throw(ArgumentError("range step cannot be zero")) - len = max(0, floor(Int, (stop-start)/step) + 1) - # Because len might be too small by 1 due to roundoff error, let's # see if the inputs have exact rational approximations (and if so, # perform all computations in terms of the rationals) step_n, step_d = rat(step) @@ -149,6 +147,9 @@ function colon{T<:Union{Float16,Float32,Float64}}(start::T, step::T, stop::T) end end # Fallback, taking start and step literally + len = max(0, floor(Int, (stop-start)/step) + 1) + stop′ = start + len*step + len += (start < stop′ <= stop) + (start > stop′ >= stop) StepRangeLen(TwicePrecision(start, zero(T)), twiceprecision(step, nbitslen(T, len, 1)), len) end diff --git a/test/ranges.jl b/test/ranges.jl index ca94a1e00b7af..7c8c6c3e56b38 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -333,6 +333,29 @@ for T = (Float32, Float64,),# BigFloat), @test [r[n:-2:1];] == [r;][n:-2:1] end +# issue #20373 (unliftable ranges with exact end points) +@test [3*0.05:0.05:0.2;] == [linspace(3*0.05,0.2,2);] == [3*0.05,0.2] +@test [0.2:-0.05:3*0.05;] == [linspace(0.2,3*0.05,2);] == [0.2,3*0.05] +@test [-3*0.05:-0.05:-0.2;] == [linspace(-3*0.05,-0.2,2);] == [-3*0.05,-0.2] +@test [-0.2:0.05:-3*0.05;] == [linspace(-0.2,-3*0.05,2);] == [-0.2,-3*0.05] + +for T = (Float32, Float64,), i = 1:2^15, n = 1:5 + start, step = randn(T), randn(T) + stop = start + (n-1)*step + r = start:step:stop + @test n == length(r) + # FIXME: these fail some small portion of the time + @test_skip start == first(r) + @test_skip stop == last(r) + # FIXME: linspace construction fails on 32-bit + Sys.WORD_SIZE == 64 || continue + l = linspace(start,stop,n) + @test n == length(l) + # FIXME: these fail some small portion of the time + @test_skip start == first(l) + @test_skip stop == last(l) +end + # linspace & ranges with very small endpoints for T = (Float32, Float64) z = zero(T)