You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2026/10/21 14:50:29 UTC
(commons-numbers) 04/04: NUMBERS-219: Correct digamma/trigamma values for infinite arguments
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
commit be86bfa9623031ee5edd425508bdac5003399657
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Wed Oct 21 15:49:37 2026 +0100
NUMBERS-219: Correct digamma/trigamma values for infinite arguments
---
.../java/org/apache/commons/numbers/gamma/Digamma.java | 15 ++++++++++++---
.../java/org/apache/commons/numbers/gamma/Trigamma.java | 11 ++++++++++-
.../org/apache/commons/numbers/gamma/DigammaTest.java | 7 ++++---
.../org/apache/commons/numbers/gamma/TrigammaTest.java | 5 +++--
src/changes/changes.xml | 6 +++++-
5 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Digamma.java b/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Digamma.java
index d80e5765..72321939 100644
--- a/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Digamma.java
+++ b/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Digamma.java
@@ -49,13 +49,20 @@ public final class Digamma {
/**
* Computes the digamma function.
*
- * This is an independently written implementation of the algorithm described in
+ * <p>Special cases:
+ * <ul>
+ * <li>If the argument is infinity, then the result is infinity.</li>
+ * <li>If the argument is negative infinity, then the result is nan.</li>
+ * <li>If the argument is nan, then the result is nan.</li>
+ * </ul>
+ *
+ * <p>This is an independently written implementation of the algorithm described in
* <a href="https://www.uv.es/~bernardo/1976AppStatist.pdf">Jose Bernardo,
* Algorithm AS 103: Psi (Digamma) Function, Applied Statistics, 1976</a>.
* A <a href="https://en.wikipedia.org/wiki/Digamma_function#Reflection_formula">
* reflection formula</a> is incorporated to improve performance on negative values.
*
- * Some of the constants have been changed to increase accuracy at the moderate
+ * <p>Some of the constants have been changed to increase accuracy at the moderate
* expense of run-time. The result should be accurate to within {@code 1e-8}.
* relative tolerance for {@code 0 < x < 1e-5} and within {@code 1e-8} absolute
* tolerance otherwise.
@@ -66,7 +73,9 @@ public final class Digamma {
*/
public static double value(double x) {
if (!Double.isFinite(x)) {
- return x;
+ // Function oscillates between infinite poles at integer values for
+ // large negative x; the -infinity limit is undefined
+ return x == Double.POSITIVE_INFINITY ? x : Double.NaN;
}
double digamma = 0;
diff --git a/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Trigamma.java b/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Trigamma.java
index 8ab1dd4b..0955fc4a 100644
--- a/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Trigamma.java
+++ b/commons-numbers-gamma/src/main/java/org/apache/commons/numbers/gamma/Trigamma.java
@@ -46,12 +46,21 @@ public final class Trigamma {
/**
* Computes the trigamma function.
*
+ * <p>Special cases:
+ * <ul>
+ * <li>If the argument is infinity, then the result is 0.</li>
+ * <li>If the argument is negative infinity, then the result is nan.</li>
+ * <li>If the argument is nan, then the result is nan.</li>
+ * </ul>
+ *
* @param x Argument.
* @return trigamma(x) to within {@code 1e-8} relative or absolute error whichever is larger.
*/
public static double value(double x) {
if (!Double.isFinite(x)) {
- return x;
+ // Function oscillates between infinite poles at integer values for
+ // large negative x; the -infinity limit is undefined
+ return x == Double.POSITIVE_INFINITY ? 0 : Double.NaN;
}
if (x < 0) {
diff --git a/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/DigammaTest.java b/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/DigammaTest.java
index a83261d2..92d439e2 100644
--- a/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/DigammaTest.java
+++ b/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/DigammaTest.java
@@ -68,9 +68,10 @@ class DigammaTest {
@Test
void testDigammaNonRealArgs() {
- Assertions.assertTrue(Double.isNaN(Digamma.value(Double.NaN)));
- Assertions.assertTrue(Double.isInfinite(Digamma.value(Double.POSITIVE_INFINITY)));
- Assertions.assertTrue(Double.isInfinite(Digamma.value(Double.NEGATIVE_INFINITY)));
+ // See NUMBERS-219
+ Assertions.assertEquals(Double.NaN, Digamma.value(Double.NaN));
+ Assertions.assertEquals(Double.POSITIVE_INFINITY, Digamma.value(Double.POSITIVE_INFINITY));
+ Assertions.assertEquals(Double.NaN, Digamma.value(Double.NEGATIVE_INFINITY));
}
private void checkRelativeError(String msg,
diff --git a/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/TrigammaTest.java b/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/TrigammaTest.java
index 22ceae6e..938143db 100644
--- a/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/TrigammaTest.java
+++ b/commons-numbers-gamma/src/test/java/org/apache/commons/numbers/gamma/TrigammaTest.java
@@ -110,9 +110,10 @@ class TrigammaTest {
@Test
void testTrigammaNonRealArgs() {
+ // See NUMBERS-219
Assertions.assertEquals(Double.NaN, Trigamma.value(Double.NaN));
- Assertions.assertEquals(Double.POSITIVE_INFINITY, Trigamma.value(Double.POSITIVE_INFINITY));
- Assertions.assertEquals(Double.NEGATIVE_INFINITY, Trigamma.value(Double.NEGATIVE_INFINITY));
+ Assertions.assertEquals(0, Trigamma.value(Double.POSITIVE_INFINITY));
+ Assertions.assertEquals(Double.NaN, Trigamma.value(Double.NEGATIVE_INFINITY));
}
}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 704ab630..59b2a940 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -56,7 +56,11 @@ If the output is not quite correct, check for invisible trailing spaces!
<release version="1.4" date="TBD" description="
New features, updates and bug fixes.
">
- <action type="fix" due-to="Aryan Ganjoo" issue="NUMBERS-218">
+ <action dev="aherbert" type="fix" due-to="Alex Herbert" issue="NUMBERS-219">
+ "Digamma/Trigamma": Value at -infinity is undefined (NaN). Value at +infinity
+ is asymptotically +infinity (digamma) and 0 (trigamma).
+ </action>
+ <action dev="aherbert" type="fix" due-to="Aryan Ganjoo" issue="NUMBERS-218">
"ArithmeticUtils.pow": Return the representable minimum int and long values for
(-2)^31 and (-2)^63 instead of reporting overflow.
</action>