From 7fcf9c88185ba53ef1dcb685ce55adec56b27efc Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Thu, 15 Feb 2024 03:38:27 +0100 Subject: [PATCH] Random: make statistical uniform tests fail less often (#52165) We have a very basic test to check that a distribution might be uniform: all the sampled elements should be unique, under certain conditions. But these conditions allowed the tests to fail too often. So allow one collision if the probability of such an event is too high. Fix #52156. --------- Co-authored-by: Kristoffer Carlsson --- stdlib/Random/test/runtests.jl | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/stdlib/Random/test/runtests.jl b/stdlib/Random/test/runtests.jl index 16a2f89753f3b..9b46951f63ff5 100644 --- a/stdlib/Random/test/runtests.jl +++ b/stdlib/Random/test/runtests.jl @@ -16,15 +16,30 @@ using Random: jump_128, jump_192, jump_128!, jump_192! import Future # randjump function test_uniform(xs::AbstractArray{T}) where {T<:AbstractFloat} - if precision(T) >= precision(Float32) # TODO: refine - @test allunique(xs) + # TODO: refine + prec = isempty(xs) ? precision(T) : precision(first(xs)) + proba_nocollision = prod((1.0 - i/2.0^prec for i=1:length(xs)-1), init=1.0) # rough estimate + xsu = Set(xs) + if (1.0 - proba_nocollision) < 2.0^-64 + @test length(xsu) == length(xs) + elseif prec > 52 && length(xs) < 3000 + # if proba of collisions is high enough, allow at most one collision; + # with the constraints on precision and length, more than one collision would happen + # with proba less than 2.0^-62 + @test length(xsu) >= length(xs)-1 end @test all(x -> zero(x) <= x < one(x), xs) end -function test_uniform(xs::AbstractArray{T}) where {T<:Integer} - if !Base.hastypemax(T) || widen(typemax(T)) - widen(typemin(T)) >= 2^30 # TODO: refine - @test allunique(xs) +function test_uniform(xs::AbstractArray{T}) where {T<:Base.BitInteger} + # TODO: refine + prec = 8*sizeof(T) + proba_nocollision = prod((1.0 - i/2.0^prec for i=1:length(xs)-1), init=1.0) + xsu = Set(xs) + if (1.0 - proba_nocollision) < 2.0^-64 + @test length(xsu) == length(xs) + elseif prec > 52 && length(xs) < 3000 + @test length(xsu) >= length(xs)-1 end end