Skip to content

Commit 88a553a

Browse files
authored
Fix promotion in cov and mean to handle integer and rational matrices (#23285)
Fixes #8080
1 parent d126c66 commit 88a553a

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

base/statistics.jl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ julia> mean!([1. 1.], v)
5959
"""
6060
function mean!(R::AbstractArray, A::AbstractArray)
6161
sum!(R, A; init=true)
62-
scale!(R, _length(R) / _length(A))
62+
scale!(R, _length(R) // max(1, _length(A)))
6363
return R
6464
end
6565

@@ -175,7 +175,7 @@ function varm!(R::AbstractArray{S}, A::AbstractArray, m::AbstractArray; correcte
175175
fill!(R, convert(S, NaN))
176176
else
177177
rn = div(_length(A), _length(R)) - Int(corrected)
178-
scale!(centralize_sumabs2!(R, A, m), one(S)/rn)
178+
scale!(centralize_sumabs2!(R, A, m), 1//rn)
179179
end
180180
return R
181181
end
@@ -335,12 +335,18 @@ unscaled_covzm(x::AbstractMatrix, y::AbstractMatrix, vardim::Int) =
335335
# covzm (with centered data)
336336

337337
covzm(x::AbstractVector; corrected::Bool=true) = unscaled_covzm(x) / (_length(x) - Int(corrected))
338-
covzm(x::AbstractMatrix, vardim::Int=1; corrected::Bool=true) =
339-
scale!(unscaled_covzm(x, vardim), inv(size(x,vardim) - Int(corrected)))
338+
function covzm(x::AbstractMatrix, vardim::Int=1; corrected::Bool=true)
339+
C = unscaled_covzm(x, vardim)
340+
T = promote_type(typeof(first(C) / 1), eltype(C))
341+
return scale!(convert(AbstractMatrix{T}, C), 1//(size(x, vardim) - corrected))
342+
end
340343
covzm(x::AbstractVector, y::AbstractVector; corrected::Bool=true) =
341344
unscaled_covzm(x, y) / (_length(x) - Int(corrected))
342-
covzm(x::AbstractVecOrMat, y::AbstractVecOrMat, vardim::Int=1; corrected::Bool=true) =
343-
scale!(unscaled_covzm(x, y, vardim), inv(_getnobs(x, y, vardim) - Int(corrected)))
345+
function covzm(x::AbstractVecOrMat, y::AbstractVecOrMat, vardim::Int=1; corrected::Bool=true)
346+
C = unscaled_covzm(x, y, vardim)
347+
T = promote_type(typeof(first(C) / 1), eltype(C))
348+
return scale!(convert(AbstractArray{T}, C), 1//(_getnobs(x, y, vardim) - corrected))
349+
end
344350

345351
# covm (with provided mean)
346352

test/statistics.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,3 +432,11 @@ end
432432
@test quantile(x, 0.5) === 3.0
433433
@test quantile(x, 1//2) === 3//1
434434
end
435+
436+
@testset "Promotion in covzm. Issue #8080" begin
437+
A = [1 -1 -1; -1 1 1; -1 1 -1; 1 -1 -1; 1 -1 1]
438+
@test Base.covzm(A) - mean(A, 1)'*mean(A, 1)*size(A, 1)/(size(A, 1) - 1) cov(A)
439+
A = [1//1 -1 -1; -1 1 1; -1 1 -1; 1 -1 -1; 1 -1 1]
440+
@test (A'A - size(A, 1)*Base.mean(A, 1)'*Base.mean(A, 1))/4 == cov(A)
441+
end
442+

0 commit comments

Comments
 (0)