stat/distuv: provide complete test coverage for F distribution
MODIFY
stat/distuv/distribution_test.go
stat/distuv/distribution_test.go
@@ -216,6 +216,22 @@ func checkProbQuantContinuous(t *testing.T, i int, xs []float64, c cumulantProbe
}
}
+type moder interface {
+ Mode() float64
+}
+
+func checkMode(t *testing.T, i int, xs []float64, m moder, dx float64, tol float64) {
+ rXs := make([]float64, len(xs))
+ for j, x := range xs {
+ rXs[j] = math.RoundToEven(x/dx) * dx
+ }
+ want, _ := stat.Mode(rXs, nil)
+ got := m.Mode()
+ if !floats.EqualWithinAbs(want, got, tol) {
+ t.Errorf("Mode mismatch case %d: want %g, got %v", i, want, got)
+ }
+}
+
// checkProbDiscrete confirms that PDF and Rand are consistent for discrete distributions.
func checkProbDiscrete(t *testing.T, i int, xs []float64, p probLogprober, tol float64) {
// Make a map of all of the unique samples.

MODIFY
stat/distuv/f_test.go
stat/distuv/f_test.go
package distuv
import (
+ "math"
"sort"
"testing"
@@ -64,12 +65,12 @@ func TestFCDF(t *testing.T) {
func TestF(t *testing.T) {
t.Parallel()
src := rand.New(rand.NewSource(1))
- for i, b := range []F{
+ for i, f := range []F{
{13, 16, src},
{42, 31, src},
{77, 92, src},
} {
- testF(t, b, i)
+ testF(t, f, i)
}
}
@@ -90,4 +91,62 @@ func testF(t *testing.T, f F, i int) {
checkExKurtosis(t, i, x, f, 1e-1)
checkSkewness(t, i, x, f, 5e-2)
checkQuantileCDFSurvival(t, i, x, f, 5e-3)
+ checkMode(t, i, x, f, 2e-2, 3e-2)
+
+ if f.NumParameters() != 2 {
+ t.Errorf("Wrong number of parameters. Got %v, want 2", f.NumParameters())
+ }
+}
+
+func TestFUndefined(t *testing.T) {
+ t.Parallel()
+ for _, d1 := range []float64{1, 100} {
+ for _, d2 := range []float64{4, 8} {
+ f := F{d1, d2, nil}
+ exKurt := f.ExKurtosis()
+ if !math.IsNaN(exKurt) {
+ t.Errorf("Expected NaN excess kurtosis for D1 = %g and D2 = %g, got %v", d1, d2, exKurt)
+ }
+ }
+ }
+ for _, d1 := range []float64{1, 100} {
+ for _, d2 := range []float64{1, 2} {
+ f := F{d1, d2, nil}
+ mean := f.Mean()
+ if !math.IsNaN(mean) {
+ t.Errorf("Expected NaN mean for D1 = %g and D2 = %g, got %v", d1, d2, mean)
+ }
+ }
+ }
+ for _, d1 := range []float64{1, 2} {
+ for _, d2 := range []float64{1, 100} {
+ f := F{d1, d2, nil}
+ mode := f.Mode()
+ if !math.IsNaN(mode) {
+ t.Errorf("Expected NaN mode for D1 = %g and D2 = %g, got %v", d1, d2, mode)
+ }
+ }
+ }
+ for _, d1 := range []float64{1, 100} {
+ for _, d2 := range []float64{3, 6} {
+ f := F{d1, d2, nil}
+ skewness := f.Skewness()
+ if !math.IsNaN(skewness) {
+ t.Errorf("Expected NaN skewness for D1 = %g and D2 = %g, got %v", d1, d2, skewness)
+ }
+ }
+ }
+ for _, d1 := range []float64{1, 100} {
+ for _, d2 := range []float64{2, 4} {
+ f := F{d1, d2, nil}
+ variance := f.Variance()
+ if !math.IsNaN(variance) {
+ t.Errorf("Expected NaN variance for D1 = %g and D2 = %g, got %v", d1, d2, variance)
+ }
+ stdDev := f.StdDev()
+ if !math.IsNaN(stdDev) {
+ t.Errorf("Expected NaN standard deviation for D1 = %g and D2 = %g, got %v", d1, d2, variance)
+ }
+ }
+ }
}

stat/distuv: provide complete test coverage for F distribution