psi.c
Go to the documentation of this file.
1 /* psi.c
2  *
3  * Psi (digamma) function
4  *
5  *
6  * SYNOPSIS:
7  *
8  * double x, y, psi();
9  *
10  * y = psi( x );
11  *
12  *
13  * DESCRIPTION:
14  *
15  * d -
16  * psi(x) = -- ln | (x)
17  * dx
18  *
19  * is the logarithmic derivative of the gamma function.
20  * For integer x,
21  * n-1
22  * -
23  * psi(n) = -EUL + > 1/k.
24  * -
25  * k=1
26  *
27  * This formula is used for 0 < n <= 10. If x is negative, it
28  * is transformed to a positive argument by the reflection
29  * formula psi(1-x) = psi(x) + pi cot(pi x).
30  * For general positive x, the argument is made greater than 10
31  * using the recurrence psi(x+1) = psi(x) + 1/x.
32  * Then the following asymptotic expansion is applied:
33  *
34  * inf. B
35  * - 2k
36  * psi(x) = log(x) - 1/2x - > -------
37  * - 2k
38  * k=1 2k x
39  *
40  * where the B2k are Bernoulli numbers.
41  *
42  * ACCURACY:
43  * Relative error (except absolute when |psi| < 1):
44  * arithmetic domain # trials peak rms
45  * IEEE 0,30 30000 1.3e-15 1.4e-16
46  * IEEE -30,0 40000 1.5e-15 2.2e-16
47  *
48  * ERROR MESSAGES:
49  * message condition value returned
50  * psi singularity x integer <=0 INFINITY
51  */
52 
53 /*
54  * Cephes Math Library Release 2.8: June, 2000
55  * Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
56  */
57 
58 /*
59  * Code for the rational approximation on [1, 2] is:
60  *
61  * (C) Copyright John Maddock 2006.
62  * Use, modification and distribution are subject to the
63  * Boost Software License, Version 1.0. (See accompanying file
64  * LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
65  */
66 
67 #include "mconf.h"
68 
69 static double A[] = {
70  8.33333333333333333333E-2,
71  -2.10927960927960927961E-2,
72  7.57575757575757575758E-3,
73  -4.16666666666666666667E-3,
74  3.96825396825396825397E-3,
75  -8.33333333333333333333E-3,
76  8.33333333333333333333E-2
77 };
78 
79 
80 static double digamma_imp_1_2(double x)
81 {
82  /*
83  * Rational approximation on [1, 2] taken from Boost.
84  *
85  * Now for the approximation, we use the form:
86  *
87  * digamma(x) = (x - root) * (Y + R(x-1))
88  *
89  * Where root is the location of the positive root of digamma,
90  * Y is a constant, and R is optimised for low absolute error
91  * compared to Y.
92  *
93  * Maximum Deviation Found: 1.466e-18
94  * At double precision, max error found: 2.452e-17
95  */
96  double r, g;
97 
98  static const float Y = 0.99558162689208984f;
99 
100  static const double root1 = 1569415565.0 / 1073741824.0;
101  static const double root2 = (381566830.0 / 1073741824.0) / 1073741824.0;
102  static const double root3 = 0.9016312093258695918615325266959189453125e-19;
103 
104  static double P[] = {
105  -0.0020713321167745952,
106  -0.045251321448739056,
107  -0.28919126444774784,
108  -0.65031853770896507,
109  -0.32555031186804491,
110  0.25479851061131551
111  };
112  static double Q[] = {
113  -0.55789841321675513e-6,
114  0.0021284987017821144,
115  0.054151797245674225,
116  0.43593529692665969,
117  1.4606242909763515,
118  2.0767117023730469,
119  1.0
120  };
121  g = x - root1;
122  g -= root2;
123  g -= root3;
124  r = polevl(x - 1.0, P, 5) / polevl(x - 1.0, Q, 6);
125 
126  return g * Y + g * r;
127 }
128 
129 
130 static double psi_asy(double x)
131 {
132  double y, z;
133 
134  if (x < 1.0e17) {
135  z = 1.0 / (x * x);
136  y = z * polevl(z, A, 6);
137  }
138  else {
139  y = 0.0;
140  }
141 
142  return log(x) - (0.5 / x) - y;
143 }
144 
145 
146 double psi(double x)
147 {
148  double y = 0.0;
149  double q, r;
150  int i, n;
151 
152  if (isnan(x)) {
153  return x;
154  }
155  else if (x == INFINITY) {
156  return x;
157  }
158  else if (x == -INFINITY) {
159  return NAN;
160  }
161  else if (x == 0) {
163  return copysign(INFINITY, -x);
164  }
165  else if (x < 0.0) {
166  /* argument reduction before evaluating tan(pi * x) */
167  r = modf(x, &q);
168  if (r == 0.0) {
170  return NAN;
171  }
172  y = -M_PI / tan(M_PI * r);
173  x = 1.0 - x;
174  }
175 
176  /* check for positive integer up to 10 */
177  if ((x <= 10.0) && (x == floor(x))) {
178  n = (int)x;
179  for (i = 1; i < n; i++) {
180  y += 1.0 / i;
181  }
182  y -= SCIPY_EULER;
183  return y;
184  }
185 
186  /* use the recurrence relation to move x into [1, 2] */
187  if (x < 1.0) {
188  y -= 1.0 / x;
189  x += 1.0;
190  }
191  else if (x < 10.0) {
192  while (x > 2.0) {
193  x -= 1.0;
194  y += 1.0 / x;
195  }
196  }
197  if ((1.0 <= x) && (x <= 2.0)) {
198  y += digamma_imp_1_2(x);
199  return y;
200  }
201 
202  /* x is large, use the asymptotic series */
203  y += psi_asy(x);
204  return y;
205 }
gtsam.examples.DogLegOptimizerExample.int
int
Definition: DogLegOptimizerExample.py:111
psi
double psi(double x)
Definition: psi.c:146
gtsam::Y
GaussianFactorGraphValuePair Y
Definition: HybridGaussianProductFactor.cpp:29
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
digamma_imp_1_2
static double digamma_imp_1_2(double x)
Definition: psi.c:80
log
const EIGEN_DEVICE_FUNC LogReturnType log() const
Definition: ArrayCwiseUnaryOps.h:128
isnan
#define isnan(X)
Definition: main.h:93
SCIPY_EULER
#define SCIPY_EULER
Definition: mconf.h:128
n
int n
Definition: BiCGSTAB_simple.cpp:1
A
Definition: test_numpy_dtypes.cpp:298
Eigen::numext::q
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:1984
polevl
static double polevl(double x, const double coef[], int N)
Definition: polevl.h:65
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
psi_asy
static double psi_asy(double x)
Definition: psi.c:130
tan
const EIGEN_DEVICE_FUNC TanReturnType tan() const
Definition: ArrayCwiseUnaryOps.h:269
g
void g(const string &key, int i)
Definition: testBTree.cpp:41
y
Scalar * y
Definition: level1_cplx_impl.h:124
Eigen::Quaternion
The quaternion class used to represent 3D orientations and rotations.
Definition: ForwardDeclarations.h:293
mconf.h
sf_error
void sf_error(const char *func_name, sf_error_t code, const char *fmt,...)
Definition: sf_error.c:41
P
static double P[]
Definition: ellpe.c:68
SF_ERROR_SINGULAR
@ SF_ERROR_SINGULAR
Definition: sf_error.h:10
NULL
#define NULL
Definition: ccolamd.c:609
M_PI
#define M_PI
Definition: mconf.h:117
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
floor
const EIGEN_DEVICE_FUNC FloorReturnType floor() const
Definition: ArrayCwiseUnaryOps.h:481


gtsam
Author(s):
autogenerated on Fri Nov 1 2024 03:34:49