1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.numbers.gamma;
18
19 /**
20 * <a href="http://en.wikipedia.org/wiki/Digamma_function">Digamma function</a>.
21 * <p>
22 * It is defined as the logarithmic derivative of the \( \Gamma \)
23 * ({@link Gamma}) function:
24 * \( \frac{d}{dx}(\ln \Gamma(x)) = \frac{\Gamma^\prime(x)}{\Gamma(x)} \).
25 * </p>
26 *
27 * @see Gamma
28 */
29 public final class Digamma {
30 /** <a href="http://en.wikipedia.org/wiki/Euler-Mascheroni_constant">Euler-Mascheroni constant</a>. */
31 private static final double GAMMA = 0.577215664901532860606512090082;
32
33 /** C limit. */
34 private static final double C_LIMIT = 49;
35 /** S limit. */
36 private static final double S_LIMIT = 1e-5;
37 /** Fraction. */
38 private static final double F_M1_12 = -1d / 12;
39 /** Fraction. */
40 private static final double F_1_120 = 1d / 120;
41 /** Fraction. */
42 private static final double F_M1_252 = -1d / 252;
43
44 /** Private constructor. */
45 private Digamma() {
46 // intentionally empty.
47 }
48
49 /**
50 * Computes the digamma function.
51 *
52 * This is an independently written implementation of the algorithm described in
53 * <a href="http://www.uv.es/~bernardo/1976AppStatist.pdf">Jose Bernardo,
54 * Algorithm AS 103: Psi (Digamma) Function, Applied Statistics, 1976</a>.
55 * A <a href="https://en.wikipedia.org/wiki/Digamma_function#Reflection_formula">
56 * reflection formula</a> is incorporated to improve performance on negative values.
57 *
58 * Some of the constants have been changed to increase accuracy at the moderate
59 * expense of run-time. The result should be accurate to within {@code 1e-8}.
60 * relative tolerance for {@code 0 < x < 1e-5} and within {@code 1e-8} absolute
61 * tolerance otherwise.
62 *
63 * @param x Argument.
64 * @return digamma(x) to within {@code 1e-8} relative or absolute error whichever
65 * is larger.
66 */
67 public static double value(double x) {
68 if (!Double.isFinite(x)) {
69 return x;
70 }
71
72 double digamma = 0;
73 if (x < 0) {
74 // Use reflection formula to fall back into positive values.
75 digamma -= Math.PI / Math.tan(Math.PI * x);
76 x = 1 - x;
77 }
78
79 if (x > 0 && x <= S_LIMIT) {
80 // Use method 5 from Bernardo AS103, accurate to O(x).
81 return digamma - GAMMA - 1 / x;
82 }
83
84 while (x < C_LIMIT) {
85 digamma -= 1 / x;
86 x += 1;
87 }
88
89 // Use method 4, accurate to O(1/x^8)
90 final double inv = 1 / (x * x);
91 // 1 1 1 1
92 // log(x) - --- - ------ + ------- - -------
93 // 2 x 12 x^2 120 x^4 252 x^6
94 digamma += Math.log(x) - 0.5 / x + inv * (F_M1_12 + inv * (F_1_120 + F_M1_252 * inv));
95
96 return digamma;
97 }
98 }