Skip to content

Commit 6eca1df

Browse files
Fix computation of range length in certain cases (fix #20373)
1 parent 9ac4cdf commit 6eca1df

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

base/twiceprecision.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ end
122122

123123
function colon{T<:Union{Float16,Float32,Float64}}(start::T, step::T, stop::T)
124124
step == 0 && throw(ArgumentError("range step cannot be zero"))
125-
len = max(0, floor(Int, (stop-start)/step) + 1)
126-
# Because len might be too small by 1 due to roundoff error, let's
127125
# see if the inputs have exact rational approximations (and if so,
128126
# perform all computations in terms of the rationals)
129127
step_n, step_d = rat(step)
@@ -149,6 +147,9 @@ function colon{T<:Union{Float16,Float32,Float64}}(start::T, step::T, stop::T)
149147
end
150148
end
151149
# Fallback, taking start and step literally
150+
len = max(0, floor(Int, (stop-start)/step) + 1)
151+
stop′ = start + len*step
152+
len += (start < stop′ <= stop) + (start > stop′ >= stop)
152153
StepRangeLen(TwicePrecision(start, zero(T)), twiceprecision(step, nbitslen(T, len, 1)), len)
153154
end
154155

test/ranges.jl

+21
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,27 @@ for T = (Float32, Float64,),# BigFloat),
333333
@test [r[n:-2:1];] == [r;][n:-2:1]
334334
end
335335

336+
# issue #20373 (unliftable ranges with exact end points)
337+
@test [3*0.05:0.05:0.2;] == [linspace(3*0.05,0.2,2);] == [3*0.05,0.2]
338+
@test [0.2:-0.05:3*0.05;] == [linspace(0.2,3*0.05,2);] == [0.2,3*0.05]
339+
@test [-3*0.05:-0.05:-0.2;] == [linspace(-3*0.05,-0.2,2);] == [-3*0.05,-0.2]
340+
@test [-0.2:0.05:-3*0.05;] == [linspace(-0.2,-3*0.05,2);] == [-0.2,-3*0.05]
341+
342+
for T = (Float32, Float64,), i = 1:2^15, n = 1:5
343+
start, step = randn(T), randn(T)
344+
stop = start + (n-1)*step
345+
r = start:step:stop
346+
@test n == length(r)
347+
# FIXME: these fail some small portion of the time
348+
@test_skip start == first(r)
349+
@test_skip stop == last(r)
350+
l = linspace(start,stop,n)
351+
@test n == length(l)
352+
# FIXME: these fail some small portion of the time
353+
@test_skip start == first(l)
354+
@test_skip stop == last(l)
355+
end
356+
336357
# linspace & ranges with very small endpoints
337358
for T = (Float32, Float64)
338359
z = zero(T)

0 commit comments

Comments
 (0)