From ba243188611a78a6a3f5a25c8a2574aca0fc4674 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Wed, 24 Mar 2021 20:54:46 +0100 Subject: [PATCH] Fix detection of NaN in median() (#73) There is no reliable way to know only from the array eltype whether entries support `isnan` or not. Better leave to the compiler to optimize out the `isa Number` check when possible. --- src/Statistics.jl | 2 +- test/runtests.jl | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Statistics.jl b/src/Statistics.jl index ac2d2426..29aae101 100644 --- a/src/Statistics.jl +++ b/src/Statistics.jl @@ -805,7 +805,7 @@ Like [`median`](@ref), but may overwrite the input vector. function median!(v::AbstractVector) isempty(v) && throw(ArgumentError("median of an empty array is undefined, $(repr(v))")) eltype(v)>:Missing && any(ismissing, v) && return missing - (eltype(v)<:AbstractFloat || eltype(v)>:AbstractFloat) && any(isnan, v) && return convert(eltype(v), NaN) + any(x -> x isa Number && isnan(x), v) && return convert(eltype(v), NaN) inds = axes(v, 1) n = length(inds) mid = div(first(inds)+last(inds),2) diff --git a/test/runtests.jl b/test/runtests.jl index e0377b46..00cdad10 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -67,6 +67,15 @@ end @test @inferred(median(Float16[1, 2, 3])) === Float16(2) @test @inferred(median(Float32[1, 2, NaN])) === NaN32 @test @inferred(median(Float32[1, 2, 3])) === 2.0f0 + + # custom type implementing minimal interface + struct A + x + end + Statistics.middle(x::A, y::A) = A(middle(x.x, y.x)) + Base.isless(x::A, y::A) = isless(x.x, y.x) + @test median([A(1), A(2)]) === A(1.5) + @test median(Any[A(1), A(2)]) === A(1.5) end @testset "mean" begin