| // Copyright 2015 The Go 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 stats | |
| import "math" | |
| // mathSign returns the sign of x: -1 if x < 0, 0 if x == 0, 1 if x > 0. | |
| // If x is NaN, it returns NaN. | |
| func mathSign(x float64) float64 { | |
| if x == 0 { | |
| return 0 | |
| } else if x < 0 { | |
| return -1 | |
| } else if x > 0 { | |
| return 1 | |
| } | |
| return nan | |
| } | |
| const smallFactLimit = 20 // 20! => 62 bits | |
| var smallFact [smallFactLimit + 1]int64 | |
| func init() { | |
| smallFact[0] = 1 | |
| fact := int64(1) | |
| for n := int64(1); n <= smallFactLimit; n++ { | |
| fact *= n | |
| smallFact[n] = fact | |
| } | |
| } | |
| // mathChoose returns the binomial coefficient of n and k. | |
| func mathChoose(n, k int) float64 { | |
| if k == 0 || k == n { | |
| return 1 | |
| } | |
| if k < 0 || n < k { | |
| return 0 | |
| } | |
| if n <= smallFactLimit { // Implies k <= smallFactLimit | |
| // It's faster to do several integer multiplications | |
| // than it is to do an extra integer division. | |
| // Remarkably, this is also faster than pre-computing | |
| // Pascal's triangle (presumably because this is very | |
| // cache efficient). | |
| numer := int64(1) | |
| for n1 := int64(n - (k - 1)); n1 <= int64(n); n1++ { | |
| numer *= n1 | |
| } | |
| denom := smallFact[k] | |
| return float64(numer / denom) | |
| } | |
| return math.Exp(lchoose(n, k)) | |
| } | |
| // mathLchoose returns math.Log(mathChoose(n, k)). | |
| func mathLchoose(n, k int) float64 { | |
| if k == 0 || k == n { | |
| return 0 | |
| } | |
| if k < 0 || n < k { | |
| return math.NaN() | |
| } | |
| return lchoose(n, k) | |
| } | |
| func lchoose(n, k int) float64 { | |
| a, _ := math.Lgamma(float64(n + 1)) | |
| b, _ := math.Lgamma(float64(k + 1)) | |
| c, _ := math.Lgamma(float64(n - k + 1)) | |
| return a - b - c | |
| } |