aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/math/gamma.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/math/gamma.go')
-rw-r--r--libgo/go/math/gamma.go43
1 files changed, 31 insertions, 12 deletions
diff --git a/libgo/go/math/gamma.go b/libgo/go/math/gamma.go
index 841ec11..cc9e869 100644
--- a/libgo/go/math/gamma.go
+++ b/libgo/go/math/gamma.go
@@ -91,23 +91,31 @@ var _gamS = [...]float64{
}
// Gamma function computed by Stirling's formula.
-// The polynomial is valid for 33 <= x <= 172.
-func stirling(x float64) float64 {
+// The pair of results must be multiplied together to get the actual answer.
+// The multiplication is left to the caller so that, if careful, the caller can avoid
+// infinity for 172 <= x <= 180.
+// The polynomial is valid for 33 <= x <= 172; larger values are only used
+// in reciprocal and produce denormalized floats. The lower precision there
+// masks any imprecision in the polynomial.
+func stirling(x float64) (float64, float64) {
+ if x > 200 {
+ return Inf(1), 1
+ }
const (
SqrtTwoPi = 2.506628274631000502417
MaxStirling = 143.01608
)
w := 1 / x
w = 1 + w*((((_gamS[0]*w+_gamS[1])*w+_gamS[2])*w+_gamS[3])*w+_gamS[4])
- y := Exp(x)
+ y1 := Exp(x)
+ y2 := 1.0
if x > MaxStirling { // avoid Pow() overflow
v := Pow(x, 0.5*x-0.25)
- y = v * (v / y)
+ y1, y2 = v, v/y1
} else {
- y = Pow(x, x-0.5) / y
+ y1 = Pow(x, x-0.5) / y1
}
- y = SqrtTwoPi * y * w
- return y
+ return y1, SqrtTwoPi * w * y2
}
// Gamma returns the Gamma function of x.
@@ -125,22 +133,26 @@ func Gamma(x float64) float64 {
switch {
case isNegInt(x) || IsInf(x, -1) || IsNaN(x):
return NaN()
+ case IsInf(x, 1):
+ return Inf(1)
case x == 0:
if Signbit(x) {
return Inf(-1)
}
return Inf(1)
- case x < -170.5674972726612 || x > 171.61447887182298:
- return Inf(1)
}
q := Abs(x)
p := Floor(q)
if q > 33 {
if x >= 0 {
- return stirling(x)
+ y1, y2 := stirling(x)
+ return y1 * y2
}
+ // Note: x is negative but (checked above) not a negative integer,
+ // so x must be small enough to be in range for conversion to int64.
+ // If |x| were >= 2⁶³ it would have to be an integer.
signgam := 1
- if ip := int(p); ip&1 == 0 {
+ if ip := int64(p); ip&1 == 0 {
signgam = -1
}
z := q - p
@@ -152,7 +164,14 @@ func Gamma(x float64) float64 {
if z == 0 {
return Inf(signgam)
}
- z = Pi / (Abs(z) * stirling(q))
+ sq1, sq2 := stirling(q)
+ absz := Abs(z)
+ d := absz * sq1 * sq2
+ if IsInf(d, 0) {
+ z = Pi / absz / sq1 / sq2
+ } else {
+ z = Pi / d
+ }
return float64(signgam) * z
}