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 <[email protected]>
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>

Reply via email to