From 0588f2cf9e43f9f72af5802feaf0af4b652c3257 Mon Sep 17 00:00:00 2001 From: Vincent Yu Date: Wed, 22 Jun 2022 01:26:56 +0800 Subject: [PATCH] Improve `middle(::AbstractRange)` performance (#116) * Restrict `middle(::AbstractRange)` eltype and improve performance * Revert eltype restriction * Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat * Fix typo: `r` -> `a` * Update test/runtests.jl Co-authored-by: Milan Bouchet-Valat * Fix CI failure * Add `middle(0:typemax(Int))` test Co-authored-by: Milan Bouchet-Valat --- src/Statistics.jl | 29 +++++++++++------------------ test/runtests.jl | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Statistics.jl b/src/Statistics.jl index b4771bed..040ac972 100644 --- a/src/Statistics.jl +++ b/src/Statistics.jl @@ -765,28 +765,16 @@ equivalent in both value and type to computing their mean (`(x + y) / 2`). middle(x::Number, y::Number) = x/2 + y/2 """ - middle(range) + middle(a::AbstractArray) -Compute the middle of a range, which consists of computing the mean of its extrema. -Since a range is sorted, the mean is performed with the first and last element. +Compute the middle of an array `a`, which consists of finding its +extrema and then computing their mean. ```jldoctest julia> using Statistics julia> middle(1:10) 5.5 -``` -""" -middle(a::AbstractRange) = middle(a[1], a[end]) - -""" - middle(a) - -Compute the middle of an array `a`, which consists of finding its -extrema and then computing their mean. - -```jldoctest -julia> using Statistics julia> a = [1,2,3.6,10.9] 4-element Vector{Float64}: @@ -801,6 +789,11 @@ julia> middle(a) """ middle(a::AbstractArray) = ((v1, v2) = extrema(a); middle(v1, v2)) +function middle(a::AbstractRange) + isempty(a) && throw(ArgumentError("middle of an empty range is undefined.")) + return middle(first(a), last(a)) +end + """ median!(v) @@ -997,9 +990,9 @@ end require_one_based_indexing(v) n = length(v) - + @assert n > 0 # this case should never happen here - + m = alpha + p * (one(alpha) - alpha - beta) aleph = n*p + oftype(p, m) j = clamp(trunc(Int, aleph), 1, n-1) @@ -1012,7 +1005,7 @@ end a = v[j] b = v[j + 1] end - + if isfinite(a) && isfinite(b) return a + γ*(b-a) else diff --git a/test/runtests.jl b/test/runtests.jl index e4d4ba81..35242c27 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -21,6 +21,15 @@ Random.seed!(123) for T in [Bool,Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,Float16,Float32,Float64] @test middle(one(T)) === middle(one(T), one(T)) end + + if VERSION < v"1.8.0-DEV.1343" + @test_throws ArgumentError middle(Int[]) + else + @test_throws MethodError middle(Int[]) + end + @test_throws ArgumentError middle(1:0) + + @test middle(0:typemax(Int)) === typemax(Int) / 2 end @testset "median" begin @@ -547,16 +556,16 @@ end @test cor(tmp, tmp) <= 1.0 @test cor(tmp, tmp2) <= 1.0 end - + @test cor(Int[]) === 1.0 @test cor([im]) === 1.0 + 0.0im @test_throws MethodError cor([]) @test_throws MethodError cor(Any[1.0]) - + @test cor([1, missing]) === 1.0 @test ismissing(cor([missing])) @test_throws MethodError cor(Any[1.0, missing]) - + @test Statistics.corm([true], 1.0) === 1.0 @test_throws MethodError Statistics.corm(Any[0.0, 1.0], 0.5) @test Statistics.corzm([true]) === 1.0 @@ -958,4 +967,4 @@ end @test isequal(cor(mx, Int[]), fill(NaN, 2, 1)) @test isequal(cov(Int[], my), fill(-0.0, 1, 3)) @test isequal(cor(Int[], my), fill(NaN, 1, 3)) -end \ No newline at end of file +end