Skip to content

Commit 48c5380

Browse files
committed
Faster NaN checks
1 parent 71a7b58 commit 48c5380

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

src/Utils.jl

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,30 @@ macro return_on_false2(flag, retval, retval2)
7474
end
7575

7676
# Fastest way to check for NaN in an array.
77-
# (due to optimizations in sum())
78-
is_bad_array(array) = !(isempty(array) || isfinite(sum(array)))
77+
# Thanks @mikmore https://discourse.julialang.org/t/fastest-way-to-check-for-inf-or-nan-in-an-array/76954/33?u=milescranmer
78+
is_bad_array(x) = !is_good_array(x)
79+
80+
function is_good_array(x::AbstractArray{T}, V::Val{unroll}=Val(16)) where {unroll,T}
81+
_zero = zero(T)
82+
83+
# Vectorized segment
84+
mask = ntuple(i -> _zero, unroll)
85+
cumulator = mask
86+
vectorized_segment = eachindex(x)[begin:unroll:(end - unroll + 1)]
87+
for i in vectorized_segment
88+
batch = ntuple(j -> @inbounds(x[i + (j - 1)]), V)
89+
cumulator = fma.(mask, batch, cumulator)
90+
end
91+
cumulator == mask || return false
92+
93+
# Tail
94+
scalar_cumulator = _zero
95+
for i in (vectorized_segment[end] + unroll):lastindex(x)
96+
scalar_cumulator = fma(_zero, @inbounds(x[i]), scalar_cumulator)
97+
end
98+
return s == z
99+
end
100+
79101
isgood(x::T) where {T<:Number} = !(isnan(x) || !isfinite(x))
80102
isgood(x) = true
81103
isbad(x) = !isgood(x)

0 commit comments

Comments
 (0)