mirror of
https://github.com/gonum/gonum.git
synced 2025-10-08 08:30:14 +08:00

* A+C: add Taesu Pyo * stat/distuv: more accurate calculation of Normal.CDF and Lognormal.CDF Fixes #577
185 lines
5.6 KiB
Go
185 lines
5.6 KiB
Go
// Copyright ©2014 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package distuv
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
|
|
"gonum.org/v1/gonum/floats"
|
|
)
|
|
|
|
// TestNormalProbs tests LogProb, Prob, CumProb, and Quantile
|
|
func TestNormalProbs(t *testing.T) {
|
|
pts := []univariateProbPoint{
|
|
{
|
|
loc: 0,
|
|
prob: oneOverRoot2Pi,
|
|
cumProb: 0.5,
|
|
logProb: -0.91893853320467274178032973640561763986139747363778341281715,
|
|
},
|
|
{
|
|
loc: -1,
|
|
prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047,
|
|
cumProb: 0.158655253931457051414767454367962077522087033273395609012605,
|
|
logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047),
|
|
},
|
|
{
|
|
loc: 1,
|
|
prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047,
|
|
cumProb: 0.841344746068542948585232545632037922477912966726604390987394,
|
|
logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047),
|
|
},
|
|
{
|
|
loc: -7,
|
|
prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12,
|
|
cumProb: 1.279812543885835004383623690780832998032844154198717929e-12,
|
|
logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12),
|
|
},
|
|
{
|
|
loc: 7,
|
|
prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12,
|
|
cumProb: 0.99999999999872018745611416499561637630921916700196715584580,
|
|
logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12),
|
|
},
|
|
}
|
|
testDistributionProbs(t, Normal{Mu: 0, Sigma: 1}, "normal", pts)
|
|
|
|
pts = []univariateProbPoint{
|
|
{
|
|
loc: 2,
|
|
prob: 0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729,
|
|
cumProb: 0.5,
|
|
logProb: math.Log(0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729),
|
|
},
|
|
{
|
|
loc: -3,
|
|
prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095,
|
|
cumProb: 0.158655253931457051414767454367962077522087033273395609012605,
|
|
logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095),
|
|
},
|
|
{
|
|
loc: 7,
|
|
prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095,
|
|
cumProb: 0.841344746068542948585232545632037922477912966726604390987394,
|
|
logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095),
|
|
},
|
|
{
|
|
loc: -33,
|
|
prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12,
|
|
cumProb: 1.279812543885835004383623690780832998032844154198717929e-12,
|
|
logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12),
|
|
},
|
|
{
|
|
loc: 37,
|
|
prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12,
|
|
cumProb: 0.99999999999872018745611416499561637630921916700196715584580,
|
|
logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12),
|
|
},
|
|
}
|
|
testDistributionProbs(t, Normal{Mu: 2, Sigma: 5}, "normal", pts)
|
|
}
|
|
|
|
func TestNormFitPrior(t *testing.T) {
|
|
testConjugateUpdate(t, func() ConjugateUpdater { return &Normal{Mu: -10, Sigma: 6} })
|
|
}
|
|
|
|
func TestNormScore(t *testing.T) {
|
|
for _, test := range []*Normal{
|
|
{
|
|
Mu: 0,
|
|
Sigma: 1,
|
|
},
|
|
{
|
|
Mu: 0.32238,
|
|
Sigma: 13.69,
|
|
},
|
|
} {
|
|
testDerivParam(t, test)
|
|
}
|
|
}
|
|
|
|
func TestNormalQuantile(t *testing.T) {
|
|
// Values from https://www.johndcook.com/blog/normal_cdf_inverse/
|
|
p := []float64{
|
|
0.0000001,
|
|
0.00001,
|
|
0.001,
|
|
0.05,
|
|
0.15,
|
|
0.25,
|
|
0.35,
|
|
0.45,
|
|
0.55,
|
|
0.65,
|
|
0.75,
|
|
0.85,
|
|
0.95,
|
|
0.999,
|
|
0.99999,
|
|
0.9999999,
|
|
}
|
|
ans := []float64{
|
|
-5.199337582187471,
|
|
-4.264890793922602,
|
|
-3.090232306167813,
|
|
-1.6448536269514729,
|
|
-1.0364333894937896,
|
|
-0.6744897501960817,
|
|
-0.38532046640756773,
|
|
-0.12566134685507402,
|
|
0.12566134685507402,
|
|
0.38532046640756773,
|
|
0.6744897501960817,
|
|
1.0364333894937896,
|
|
1.6448536269514729,
|
|
3.090232306167813,
|
|
4.264890793922602,
|
|
5.199337582187471,
|
|
}
|
|
for i, v := range p {
|
|
got := UnitNormal.Quantile(v)
|
|
if !floats.EqualWithinAbsOrRel(got, ans[i], 1e-10, 1e-10) {
|
|
t.Errorf("Quantile mismatch. Case %d, want: %v, got: %v", i, ans[i], got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormFitPanic(t *testing.T) {
|
|
n := Normal{Mu: 0, Sigma: 1}
|
|
defer func() {
|
|
r := recover()
|
|
if r != nil {
|
|
t.Errorf("unexpected panic for Fit call: %v", r)
|
|
}
|
|
}()
|
|
n.Fit(make([]float64, 10), nil)
|
|
}
|
|
|
|
func BenchmarkNormalQuantile(b *testing.B) {
|
|
n := Normal{Mu: 2, Sigma: 3.1}
|
|
ps := make([]float64, 1000) // ensure there are small values
|
|
floats.Span(ps, 0, 1)
|
|
for i := 0; i < b.N; i++ {
|
|
for _, v := range ps {
|
|
x := n.Quantile(v)
|
|
_ = x
|
|
}
|
|
}
|
|
}
|
|
|
|
// See https://github.com/gonum/gonum/issues/577 for details.
|
|
func TestNormalIssue577(t *testing.T) {
|
|
x := -36.0
|
|
max := 1.e-282
|
|
cdf := Normal{Mu: 0, Sigma: 1}.CDF(x)
|
|
if cdf <= 0 {
|
|
t.Errorf("Normal{0,1}.CDF(%e) should be positive. got: %e", x, cdf)
|
|
}
|
|
if cdf > max {
|
|
t.Errorf("Normal{0,1}.CDF(%e) is greater than %e. got: %e", x, max, cdf)
|
|
}
|
|
}
|