stat/distuv: improve Gamma.Rand performances
MODIFY
stat/distuv/beta_test.go
stat/distuv/beta_test.go
@@ -49,7 +49,7 @@ func TestBetaRand(t *testing.T) {
func testBeta(t *testing.T, b Beta, i int) {
const (
tol = 1e-2
- n = 5e4
+ n = 1e5
bins = 10
)
x := make([]float64, n)

MODIFY
stat/distuv/gamma.go
stat/distuv/gamma.go
@@ -219,11 +219,17 @@ func (g Gamma) Rand() float64 {
d := a - 1.0/3
c := 1 / (3 * math.Sqrt(d))
for {
- u := -exprnd()
x := normrnd()
v := 1 + x*c
+ if v <= 0.0 {
+ continue
+ }
v = v * v * v
- if u < 0.5*x*x+d*(1-v+math.Log(v)) {
+ u := unifrnd()
+ if u < 1.0-0.0331*(x*x)*(x*x) {
+ return d * v / b
+ }
+ if math.Log(u) < 0.5*x*x+d*(1-v+math.Log(v)) {
return d * v / b
}
}

MODIFY
stat/distuv/gamma_test.go
stat/distuv/gamma_test.go
package distuv
import (
+ "fmt"
"math"
"sort"
"testing"
@@ -116,3 +117,20 @@ func TestGammaPanics(t *testing.T) {
t.Errorf("Expected Rand panic for Alpha <= 0")
}
}
+
+func BenchmarkGammaRand(b *testing.B) {
+ src := rand.New(rand.NewSource(1))
+ for i, g := range []Gamma{
+ {Alpha: 0.1, Beta: 0.8, Src: src},
+ {Alpha: 0.5, Beta: 0.8, Src: src},
+ {Alpha: 1, Beta: 1, Src: src},
+ {Alpha: 1.6, Beta: 0.4, Src: src},
+ {Alpha: 30, Beta: 1.7, Src: src},
+ } {
+ b.Run(fmt.Sprintf("case %d", i), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ g.Rand()
+ }
+ })
+ }
+}

MODIFY
stat/distuv/inversegamma_test.go
stat/distuv/inversegamma_test.go
@@ -42,7 +42,7 @@ func TestInverseGamma(t *testing.T) {
func testInverseGamma(t *testing.T, f InverseGamma, i int) {
const (
tol = 1e-2
- n = 1e6
+ n = 2e6
bins = 50
)
x := make([]float64, n)

MODIFY
stat/distuv/studentst_test.go
stat/distuv/studentst_test.go
@@ -50,7 +50,7 @@ func TestStudentsT(t *testing.T) {
func testStudentsT(t *testing.T, c StudentsT, i int) {
const (
tol = 1e-2
- n = 1e5
+ n = 3e5
bins = 50
)
x := make([]float64, n)

stat/distuv: improve Gamma.Rand performances