Skip to content

Commit b30daed

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 952f987 commit b30daed

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

base/range.jl

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

13941394
function _in_range(x, r::AbstractRange)
1395-
if !isfinite(x)
1396-
return false
1397-
elseif iszero(step(r))
1398-
return !isempty(r) && first(r) == x
1399-
else
1400-
n = round(Integer, (x - first(r)) / step(r)) + 1
1401-
return n >= 1 && n <= length(r) && r[n] == x
1402-
end
1395+
isempty(r) && return false
1396+
f, l = first(r), last(r)
1397+
# check for NaN, Inf, and large x that may overflow in the next calculation
1398+
f <= x <= l || l <= x <= f || return false
1399+
iszero(step(r)) && return true
1400+
n = round(Integer, (x - f) / step(r)) + 1
1401+
n >= 1 && n <= length(r) && r[n] == x
14031402
end
14041403
in(x::Real, r::AbstractRange{<:Real}) = _in_range(x, r)
14051404
# This method needs to be defined separately since -(::T, ::T) can be implemented

test/ranges.jl

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,10 @@ end
518518
@test !(3.5 in 1:5)
519519
@test (3 in 1:5)
520520
@test (3 in 5:-1:1)
521-
#@test (3 in 3+0*(1:5))
522-
#@test !(4 in 3+0*(1:5))
521+
@test (3 in 3 .+ 0*(1:5))
522+
@test !(4 in 3 .+ 0*(1:5))
523+
@test 0. in (0. .* (1:10))
524+
@test !(0.1 in (0. .* (1:10)))
523525

524526
let r = 0.0:0.01:1.0
525527
@test (r[30] in r)
@@ -536,8 +538,17 @@ end
536538
x = (NaN16, Inf32, -Inf64, 1//0, -1//0)
537539
@test !(x in r)
538540
end
541+
542+
@test 1e40 0:1.0 # Issue #45747
543+
@test 1e20 0:1e-20:1e-20
544+
@test 1e20 0:1e-20
545+
@test 1.0 0:1e-20:1e-20
546+
@test 0.5 0:1e-20:1e-20
547+
@test 1 0:1e-20:1e-20
548+
549+
@test_broken 17.0 0:1e40 # Don't support really long ranges
539550
end
540-
@testset "in() works across types, including non-numeric types (#21728)" begin
551+
@testset "in() works across types, including non-numeric types (#21728 and #45646)" begin
541552
@test 1//1 in 1:3
542553
@test 1//1 in 1.0:3.0
543554
@test !(5//1 in 1:3)
@@ -558,6 +569,22 @@ end
558569
@test !(Complex(1, 0) in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05))
559570
@test !in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05))
560571
@test !("a" in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05))
572+
573+
# We use Ducks because of their propensity to stand in a row and because we know
574+
# that no additional methods (e.g. isfinite) are defined specifically for Ducks.
575+
struct Duck
576+
location::Int
577+
end
578+
Base.:+(x::Duck, y::Int) = Duck(x.location + y)
579+
Base.:-(x::Duck, y::Int) = Duck(x.location - y)
580+
Base.:-(x::Duck, y::Duck) = x.location - y.location
581+
Base.isless(x::Duck, y::Duck) = isless(x.location, y.location)
582+
583+
@test Duck(3) Duck(1):2:Duck(5)
584+
@test Duck(3) Duck(5):-2:Duck(2)
585+
@test Duck(4) Duck(5):-2:Duck(1)
586+
@test Duck(4) Duck(1):Duck(5)
587+
@test Duck(0) Duck(1):Duck(5)
561588
end
562589
end
563590
@testset "indexing range with empty range (#4309)" begin

0 commit comments

Comments
 (0)