mirror of
https://github.com/gonum/gonum.git
synced 2025-10-23 15:13:31 +08:00
161 lines
3.2 KiB
Go
161 lines
3.2 KiB
Go
// Copyright ©2016 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.
|
|
|
|
/*
|
|
* Cephes Math Library Release 2.4: March,1996
|
|
* Copyright 1984, 1996 by Stephen L. Moshier
|
|
*/
|
|
|
|
/*
|
|
* Adapted from scipy's cephes unity.c
|
|
*/
|
|
|
|
package cephes
|
|
|
|
import "math"
|
|
|
|
const (
|
|
invSqrt2 float64 = 1 / math.Sqrt2
|
|
pi4 float64 = math.Pi / 4
|
|
euler float64 = 0.577215664901532860606512090082402431 // Euler constant
|
|
)
|
|
|
|
/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
|
|
* 1/sqrt(2) <= x < sqrt(2)
|
|
* Theoretical peak relative error = 2.32e-20
|
|
*/
|
|
var lP = []float64{
|
|
4.5270000862445199635215E-5,
|
|
4.9854102823193375972212E-1,
|
|
6.5787325942061044846969E0,
|
|
2.9911919328553073277375E1,
|
|
6.0949667980987787057556E1,
|
|
5.7112963590585538103336E1,
|
|
2.0039553499201281259648E1,
|
|
}
|
|
|
|
var lQ = []float64{
|
|
1.5062909083469192043167E1,
|
|
8.3047565967967209469434E1,
|
|
2.2176239823732856465394E2,
|
|
3.0909872225312059774938E2,
|
|
2.1642788614495947685003E2,
|
|
6.0118660497603843919306E1,
|
|
}
|
|
|
|
// log1p computes log(1 + x)
|
|
func log1p(x float64) float64 {
|
|
z := 1 + x
|
|
if z < invSqrt2 || z > math.Sqrt2 {
|
|
return math.Log(z)
|
|
}
|
|
z = x * x
|
|
z = -0.5*z + x*(z*polevl(x, lP, 6)/p1evl(x, lQ, 6))
|
|
return x + z
|
|
}
|
|
|
|
// log1pmx computes log(1 + x) - x
|
|
func log1pmx(x float64) float64 {
|
|
if math.Abs(x) < 0.5 {
|
|
xfac := x
|
|
res := 0.0
|
|
|
|
var term float64
|
|
for n := 2; n < maxIter; n++ {
|
|
xfac *= -x
|
|
term = xfac / float64(n)
|
|
res += term
|
|
if math.Abs(term) < machEp*math.Abs(res) {
|
|
break
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
return log1p(x) - x
|
|
}
|
|
|
|
/* e^x = 1 + 2x P(x^2)/( Q(x^2) - P(x^2) )
|
|
* -0.5 <= x <= 0.5
|
|
*/
|
|
|
|
var eP = []float64{
|
|
1.2617719307481059087798E-4,
|
|
3.0299440770744196129956E-2,
|
|
9.9999999999999999991025E-1,
|
|
}
|
|
|
|
var eQ = []float64{
|
|
3.0019850513866445504159E-6,
|
|
2.5244834034968410419224E-3,
|
|
2.2726554820815502876593E-1,
|
|
2.0000000000000000000897E0,
|
|
}
|
|
|
|
// expm1 computes expm1(x) = exp(x) - 1
|
|
func expm1(x float64) float64 {
|
|
if math.IsInf(x, 0) {
|
|
if math.IsNaN(x) || x > 0 {
|
|
return x
|
|
}
|
|
return -1
|
|
}
|
|
if x < -0.5 || x > 0.5 {
|
|
return math.Exp(x) - 1
|
|
}
|
|
xx := x * x
|
|
r := x * polevl(xx, eP, 2)
|
|
r = r / (polevl(xx, eQ, 3) - r)
|
|
return r + r
|
|
}
|
|
|
|
var coscof = []float64{
|
|
4.7377507964246204691685E-14,
|
|
-1.1470284843425359765671E-11,
|
|
2.0876754287081521758361E-9,
|
|
-2.7557319214999787979814E-7,
|
|
2.4801587301570552304991E-5,
|
|
-1.3888888888888872993737E-3,
|
|
4.1666666666666666609054E-2,
|
|
}
|
|
|
|
// cosm1 computes cosm1(x) = cos(x) - 1
|
|
func cosm1(x float64) float64 {
|
|
if x < -pi4 || x > pi4 {
|
|
return math.Cos(x) - 1
|
|
}
|
|
xx := x * x
|
|
xx = -0.5*xx + xx*xx*polevl(xx, coscof, 6)
|
|
return xx
|
|
}
|
|
|
|
// lgam1pTayler computes lgam(x + 1) around x = 0 using its Taylor series.
|
|
func lgam1pTaylor(x float64) float64 {
|
|
if x == 0 {
|
|
return 0
|
|
}
|
|
res := -euler * x
|
|
xfac := -x
|
|
for n := 2; n < 42; n++ {
|
|
nf := float64(n)
|
|
xfac *= -x
|
|
coeff := Zeta(nf, 1) * xfac / nf
|
|
res += coeff
|
|
if math.Abs(coeff) < machEp*math.Abs(res) {
|
|
break
|
|
}
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
// lgam1p computes lgam(x + 1).
|
|
func lgam1p(x float64) float64 {
|
|
if math.Abs(x) <= 0.5 {
|
|
return lgam1pTaylor(x)
|
|
} else if math.Abs(x-1) < 0.5 {
|
|
return math.Log(x) + lgam1pTaylor(x-1)
|
|
}
|
|
return lgam(x + 1)
|
|
}
|