Skip to content

Commit 4a64b23

Browse files
LilithHafnerViralBShah
authored andcommitted
Replace isfinite check in ranges with lo ≤ x ≤ hi (#45646)
Co-authored-by: Viral B. Shah <ViralBShah@users.noreply.github.com> (cherry picked from commit 5811825)
1 parent e312a36 commit 4a64b23

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

base/range.jl

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,14 +1073,13 @@ function sum(r::AbstractRange{<:Real})
10731073
end
10741074

10751075
function _in_range(x, r::AbstractRange)
1076-
if !isfinite(x)
1077-
return false
1078-
elseif iszero(step(r))
1079-
return !isempty(r) && first(r) == x
1080-
else
1081-
n = round(Integer, (x - first(r)) / step(r)) + 1
1082-
return n >= 1 && n <= length(r) && r[n] == x
1083-
end
1076+
isempty(r) && return false
1077+
f, l = first(r), last(r)
1078+
# check for NaN, Inf, and large x that may overflow in the next calculation
1079+
f <= x <= l || l <= x <= f || return false
1080+
iszero(step(r)) && return true
1081+
n = round(Integer, (x - f) / step(r)) + 1
1082+
n >= 1 && n <= length(r) && r[n] == x
10841083
end
10851084
in(x::Real, r::AbstractRange{<:Real}) = _in_range(x, r)
10861085
# This method needs to be defined separately since -(::T, ::T) can be implemented

test/ranges.jl

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,8 @@ end
422422
@test !(3.5 in 1:5)
423423
@test (3 in 1:5)
424424
@test (3 in 5:-1:1)
425-
#@test (3 in 3+0*(1:5))
426-
#@test !(4 in 3+0*(1:5))
425+
@test 0. in (0. .* (1:10))
426+
@test !(0.1 in (0. .* (1:10)))
427427

428428
let r = 0.0:0.01:1.0
429429
@test (r[30] in r)
@@ -440,8 +440,17 @@ end
440440
x = (NaN16, Inf32, -Inf64, 1//0, -1//0)
441441
@test !(x in r)
442442
end
443+
444+
@test 1e40 0:1.0 # Issue #45747
445+
@test 1e20 0:1e-20:1e-20
446+
@test 1e20 0:1e-20
447+
@test 1.0 0:1e-20:1e-20
448+
@test 0.5 0:1e-20:1e-20
449+
@test 1 0:1e-20:1e-20
450+
451+
@test_broken 17.0 0:1e40 # Don't support really long ranges
443452
end
444-
@testset "in() works across types, including non-numeric types (#21728)" begin
453+
@testset "in() works across types, including non-numeric types (#21728 and #45646)" begin
445454
@test 1//1 in 1:3
446455
@test 1//1 in 1.0:3.0
447456
@test !(5//1 in 1:3)
@@ -462,6 +471,22 @@ end
462471
@test !(Complex(1, 0) in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05))
463472
@test !in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05))
464473
@test !("a" in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05))
474+
475+
# We use Ducks because of their propensity to stand in a row and because we know
476+
# that no additional methods (e.g. isfinite) are defined specifically for Ducks.
477+
struct Duck
478+
location::Int
479+
end
480+
Base.:+(x::Duck, y::Int) = Duck(x.location + y)
481+
Base.:-(x::Duck, y::Int) = Duck(x.location - y)
482+
Base.:-(x::Duck, y::Duck) = x.location - y.location
483+
Base.isless(x::Duck, y::Duck) = isless(x.location, y.location)
484+
485+
@test Duck(3) Duck(1):2:Duck(5)
486+
@test Duck(3) Duck(5):-2:Duck(2)
487+
@test Duck(4) Duck(5):-2:Duck(1)
488+
@test Duck(4) Duck(1):Duck(5)
489+
@test Duck(0) Duck(1):Duck(5)
465490
end
466491
end
467492
@testset "indexing range with empty range (#4309)" begin

0 commit comments

Comments
 (0)