Skip to content

Commit 0588f2c

Browse files
vyunalimilan
andauthored
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 <nalimilan@club.fr> * Fix typo: `r` -> `a` * Update test/runtests.jl Co-authored-by: Milan Bouchet-Valat <nalimilan@club.fr> * Fix CI failure * Add `middle(0:typemax(Int))` test Co-authored-by: Milan Bouchet-Valat <nalimilan@club.fr>
1 parent 576db0f commit 0588f2c

File tree

2 files changed

+24
-22
lines changed

2 files changed

+24
-22
lines changed

src/Statistics.jl

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -765,28 +765,16 @@ equivalent in both value and type to computing their mean (`(x + y) / 2`).
765765
middle(x::Number, y::Number) = x/2 + y/2
766766

767767
"""
768-
middle(range)
768+
middle(a::AbstractArray)
769769
770-
Compute the middle of a range, which consists of computing the mean of its extrema.
771-
Since a range is sorted, the mean is performed with the first and last element.
770+
Compute the middle of an array `a`, which consists of finding its
771+
extrema and then computing their mean.
772772
773773
```jldoctest
774774
julia> using Statistics
775775
776776
julia> middle(1:10)
777777
5.5
778-
```
779-
"""
780-
middle(a::AbstractRange) = middle(a[1], a[end])
781-
782-
"""
783-
middle(a)
784-
785-
Compute the middle of an array `a`, which consists of finding its
786-
extrema and then computing their mean.
787-
788-
```jldoctest
789-
julia> using Statistics
790778
791779
julia> a = [1,2,3.6,10.9]
792780
4-element Vector{Float64}:
@@ -801,6 +789,11 @@ julia> middle(a)
801789
"""
802790
middle(a::AbstractArray) = ((v1, v2) = extrema(a); middle(v1, v2))
803791

792+
function middle(a::AbstractRange)
793+
isempty(a) && throw(ArgumentError("middle of an empty range is undefined."))
794+
return middle(first(a), last(a))
795+
end
796+
804797
"""
805798
median!(v)
806799
@@ -997,9 +990,9 @@ end
997990
require_one_based_indexing(v)
998991

999992
n = length(v)
1000-
993+
1001994
@assert n > 0 # this case should never happen here
1002-
995+
1003996
m = alpha + p * (one(alpha) - alpha - beta)
1004997
aleph = n*p + oftype(p, m)
1005998
j = clamp(trunc(Int, aleph), 1, n-1)
@@ -1012,7 +1005,7 @@ end
10121005
a = v[j]
10131006
b = v[j + 1]
10141007
end
1015-
1008+
10161009
if isfinite(a) && isfinite(b)
10171010
return a + γ*(b-a)
10181011
else

test/runtests.jl

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ Random.seed!(123)
2121
for T in [Bool,Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,Float16,Float32,Float64]
2222
@test middle(one(T)) === middle(one(T), one(T))
2323
end
24+
25+
if VERSION < v"1.8.0-DEV.1343"
26+
@test_throws ArgumentError middle(Int[])
27+
else
28+
@test_throws MethodError middle(Int[])
29+
end
30+
@test_throws ArgumentError middle(1:0)
31+
32+
@test middle(0:typemax(Int)) === typemax(Int) / 2
2433
end
2534

2635
@testset "median" begin
@@ -547,16 +556,16 @@ end
547556
@test cor(tmp, tmp) <= 1.0
548557
@test cor(tmp, tmp2) <= 1.0
549558
end
550-
559+
551560
@test cor(Int[]) === 1.0
552561
@test cor([im]) === 1.0 + 0.0im
553562
@test_throws MethodError cor([])
554563
@test_throws MethodError cor(Any[1.0])
555-
564+
556565
@test cor([1, missing]) === 1.0
557566
@test ismissing(cor([missing]))
558567
@test_throws MethodError cor(Any[1.0, missing])
559-
568+
560569
@test Statistics.corm([true], 1.0) === 1.0
561570
@test_throws MethodError Statistics.corm(Any[0.0, 1.0], 0.5)
562571
@test Statistics.corzm([true]) === 1.0
@@ -958,4 +967,4 @@ end
958967
@test isequal(cor(mx, Int[]), fill(NaN, 2, 1))
959968
@test isequal(cov(Int[], my), fill(-0.0, 1, 3))
960969
@test isequal(cor(Int[], my), fill(NaN, 1, 3))
961-
end
970+
end

0 commit comments

Comments
 (0)