This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-math.git


The following commit(s) were added to refs/heads/master by this push:
     new bc8a9f394 Fix int overflow hang in DfpMath.pow for exponents above 
2^30 (#346)
bc8a9f394 is described below

commit bc8a9f3948c6e491fa746e932f4c29c627160fa2
Author: insaf021 <[email protected]>
AuthorDate: Tue Nov 3 16:27:45 2026 +0530

    Fix int overflow hang in DfpMath.pow for exponents above 2^30 (#346)
---
 .../commons/math4/legacy/core/dfp/DfpMath.java     | 17 +++++++++-------
 .../commons/math4/legacy/core/dfp/DfpMathTest.java | 23 ++++++++++++++++++++++
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git 
a/commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/dfp/DfpMath.java
 
b/commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/dfp/DfpMath.java
index d3820a050..343455af4 100644
--- 
a/commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/dfp/DfpMath.java
+++ 
b/commons-math-legacy-core/src/main/java/org/apache/commons/math4/legacy/core/dfp/DfpMath.java
@@ -215,31 +215,34 @@ public final class DfpMath {
             return result;
         }
 
-        if (a < 0) {
+        // Use long arithmetic: -Integer.MIN_VALUE and 2 * trial for
+        // exponents above 2^30 would otherwise overflow and never terminate
+        long n = a;
+        if (n < 0) {
             invert = true;
-            a = -a;
+            n = -n;
         }
 
         // Exponentiate by successive squaring
         do {
             Dfp r = new Dfp(base);
             Dfp prevr;
-            int trial = 1;
-            int prevtrial;
+            long trial = 1;
+            long prevtrial;
 
             do {
                 prevr = new Dfp(r);
                 prevtrial = trial;
                 r = r.multiply(r);
                 trial *= 2;
-            } while (a > trial);
+            } while (n > trial);
 
             r = prevr;
             trial = prevtrial;
 
-            a -= trial;
+            n -= trial;
             result = result.multiply(r);
-        } while (a >= 1);
+        } while (n >= 1);
 
         if (invert) {
             result = base.getOne().divide(result);
diff --git 
a/commons-math-legacy-core/src/test/java/org/apache/commons/math4/legacy/core/dfp/DfpMathTest.java
 
b/commons-math-legacy-core/src/test/java/org/apache/commons/math4/legacy/core/dfp/DfpMathTest.java
index 005df7d34..7b246d080 100644
--- 
a/commons-math-legacy-core/src/test/java/org/apache/commons/math4/legacy/core/dfp/DfpMathTest.java
+++ 
b/commons-math-legacy-core/src/test/java/org/apache/commons/math4/legacy/core/dfp/DfpMathTest.java
@@ -17,10 +17,13 @@
 
 package org.apache.commons.math4.legacy.core.dfp;
 
+import java.time.Duration;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
 
 public class DfpMathTest {
 
@@ -584,4 +587,24 @@ public class DfpMathTest {
              DfpField.FLAG_INEXACT, "sin #27");
     }
 
+    @Test
+    public void testPowLargeIntegerExponent() {
+        // Exponents beyond 2^30 in magnitude overflowed the int loop control
+        // in pow(Dfp, int) and the call never returned.
+        Assertions.assertTimeoutPreemptively(Duration.ofSeconds(30), () -> {
+            final Dfp one = factory.getOne();
+            final Dfp minusOne = one.negate();
+            final Dfp two = factory.getTwo();
+
+            Assert.assertEquals(one, DfpMath.pow(one, (1 << 30) + 1));
+            Assert.assertEquals(one, DfpMath.pow(one, Integer.MIN_VALUE));
+            Assert.assertEquals(minusOne, DfpMath.pow(minusOne, 
Integer.MAX_VALUE));
+            Assert.assertEquals(one, DfpMath.pow(minusOne, Integer.MIN_VALUE));
+            Assert.assertTrue(DfpMath.pow(two, 
Integer.MAX_VALUE).isInfinite());
+            Assert.assertTrue(DfpMath.pow(two, Integer.MIN_VALUE).isZero());
+            Assert.assertTrue(one.scalb(Integer.MIN_VALUE).isZero());
+            factory.clearIEEEFlags();
+        });
+    }
+
 }

Reply via email to