You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ps...@apache.org on 2009/05/24 08:03:19 UTC
svn commit: r778091 - in /commons/proper/math/trunk/src:
java/org/apache/commons/math/special/Gamma.java site/xdoc/changes.xml
test/org/apache/commons/math/special/GammaTest.java
Author: psteitz
Date: Sun May 24 06:03:19 2009
New Revision: 778091
URL: http://svn.apache.org/viewvc?rev=778091&view=rev
Log:
Added digamma function.
JIRA: MATH-267
Contributed by Ted Dunning
Modified:
commons/proper/math/trunk/src/java/org/apache/commons/math/special/Gamma.java
commons/proper/math/trunk/src/site/xdoc/changes.xml
commons/proper/math/trunk/src/test/org/apache/commons/math/special/GammaTest.java
Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/special/Gamma.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/special/Gamma.java?rev=778091&r1=778090&r2=778091&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/special/Gamma.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/special/Gamma.java Sun May 24 06:03:19 2009
@@ -33,6 +33,9 @@
/** Serializable version identifier */
private static final long serialVersionUID = -6587513359895466954L;
+ /** <a href="http://en.wikipedia.org/wiki/Euler-Mascheroni_constant">Euler-Mascheroni constant</a> */
+ public static final double GAMMA = 0.577215664901532860606512090082;
+
/** Maximum allowed numerical error. */
private static final double DEFAULT_EPSILON = 10e-15;
@@ -59,7 +62,7 @@
/** Avoid repeated computation of log of 2 PI in logGamma */
private static final double HALF_LOG_2_PI = 0.5 * Math.log(2.0 * Math.PI);
-
+
/**
* Default constructor. Prohibit instantiation.
*/
@@ -261,4 +264,45 @@
return ret;
}
+
+
+ // limits for switching algorithm in digamma
+ /** C limit */
+ private static final double C_LIMIT = 49;
+ /** S limit */
+ private static final double S_LIMIT = 1e-5;
+
+ /**
+ * <p>Computes the <a href="http://en.wikipedia.org/wiki/Digamma_function">digamma function</a>
+ * using the algorithm defined in <br/>
+ * Jose Bernardo, Algorithm AS 103: Psi (Digamma) Function, Applied Statistics, 1976.</p>
+ *
+ * <p>Some of the constants have been changed to increase accuracy at the moderate expense
+ * of run-time performance. The result should be accurate to within 10^-8 absolute tolerance for
+ * x >= 10^-5 and within 10^-8 relative tolerance for x > 0.</p>
+ *
+ * <p> Performance for large negative values of x will be quite expensive (proportional to
+ * |x|). Accuracy for negative values of x should be about 10^-8 absolute for results
+ * less than 10^5 and 10^-8 relative for results larger than that.
+ * @param x argument
+ * @return value of the digamma function
+ */
+ public static double digamma(double x) {
+ if (x > 0 && x <= S_LIMIT) {
+ // use method 5 from Bernardo AS103
+ // accurate to O(x)
+ return -GAMMA - 1 / x;
+ }
+
+ if (x >= C_LIMIT) {
+ // use method 4 (accurate to O(1/x^8)
+ double inv = 1 / (x * x);
+ // 1 1 1 1
+ // log(x) - --- - ------ - ------- - -------
+ // 2 x 12 x^2 120 x^4 252 x^6
+ return Math.log(x) - 0.5 / x - inv * ((1.0 / 12) + inv * (1.0 / 120 - inv / 252));
+ }
+
+ return digamma(x + 1) - 1 / x;
+ }
}
Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=778091&r1=778090&r2=778091&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Sun May 24 06:03:19 2009
@@ -39,6 +39,9 @@
</properties>
<body>
<release version="2.0" date="TBD" description="TBD">
+ <action dev="psteitz" type="add" issue="MATH-267" due=to="Ted Dunning">
+ Added digamma function.
+ </action>
<action dev="psteitz" type="add" issue="MATH-136" due=to="John Gant">
Added Spearman's rank correlation (SpearmansCorrelation).
</action>
Modified: commons/proper/math/trunk/src/test/org/apache/commons/math/special/GammaTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/special/GammaTest.java?rev=778091&r1=778090&r2=778091&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/org/apache/commons/math/special/GammaTest.java (original)
+++ commons/proper/math/trunk/src/test/org/apache/commons/math/special/GammaTest.java Sun May 24 06:03:19 2009
@@ -25,10 +25,7 @@
* @version $Revision$ $Date$
*/
public class GammaTest extends TestCase {
- /**
- * Constructor for BetaTest.
- * @param name
- */
+
public GammaTest(String name) {
super(name);
}
@@ -92,4 +89,37 @@
public void testLogGammaPositive() {
testLogGamma(0.6931471805599457, 3.0);
}
+
+ public void testDigammaLargeArgs() {
+ double eps = 1e-8;
+ assertEquals(4.6001618527380874002, Gamma.digamma(100), eps);
+ assertEquals(3.9019896734278921970, Gamma.digamma(50), eps);
+ assertEquals(2.9705239922421490509, Gamma.digamma(20), eps);
+ assertEquals(2.9958363947076465821, Gamma.digamma(20.5), eps);
+ assertEquals(2.2622143570941481605, Gamma.digamma(10.1), eps);
+ assertEquals(2.1168588189004379233, Gamma.digamma(8.8), eps);
+ assertEquals(1.8727843350984671394, Gamma.digamma(7), eps);
+ assertEquals(0.42278433509846713939, Gamma.digamma(2), eps);
+ assertEquals(-100.56088545786867450, Gamma.digamma(0.01), eps);
+ assertEquals(-4.0390398965921882955, Gamma.digamma(-0.8), eps);
+ assertEquals(4.2003210041401844726, Gamma.digamma(-6.3), eps);
+ }
+
+ public void testDigammaSmallArgs() {
+ // values for negative powers of 10 from 1 to 30 as computed by webMathematica with 20 digits
+ // see functions.wolfram.com
+ double[] expected = {-10.423754940411076795, -100.56088545786867450, -1000.5755719318103005,
+ -10000.577051183514335, -100000.57719921568107, -1.0000005772140199687e6, -1.0000000577215500408e7,
+ -1.0000000057721564845e8, -1.0000000005772156633e9, -1.0000000000577215665e10, -1.0000000000057721566e11,
+ -1.0000000000005772157e12, -1.0000000000000577216e13, -1.0000000000000057722e14, -1.0000000000000005772e15, -1e+16,
+ -1e+17, -1e+18, -1e+19, -1e+20, -1e+21, -1e+22, -1e+23, -1e+24, -1e+25, -1e+26,
+ -1e+27, -1e+28, -1e+29, -1e+30};
+ for (double n = 1; n < 30; n++) {
+ checkRelativeError(String.format("Test %.0f: ", n), expected[(int) (n - 1)], Gamma.digamma(Math.pow(10.0, -n)), 1e-8);
+ }
+ }
+
+ private void checkRelativeError(String msg, double expected, double actual, double tolerance) {
+ assertEquals(msg, expected, actual, Math.abs(tolerance * actual));
+ }
}