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();
+ });
+ }
+
}