From 40223343f0db5d4a0ba70024646556e1267cb111 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 30 Mar 2009 15:43:14 +0000 Subject: [PATCH] Added some utility functions to compute powers with integral types (int, long, BigInteger) git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@760014 13f79535-47bb-0310-9956-ffa450edef68 --- .../commons/math/MessagesResources_fr.java | 2 + .../apache/commons/math/util/MathUtils.java | 201 ++++++++++++++++++ src/site/xdoc/changes.xml | 3 + .../commons/math/util/MathUtilsTest.java | 77 +++++++ 4 files changed, 283 insertions(+) diff --git a/src/java/org/apache/commons/math/MessagesResources_fr.java b/src/java/org/apache/commons/math/MessagesResources_fr.java index 640c81e21..b1e9026dd 100644 --- a/src/java/org/apache/commons/math/MessagesResources_fr.java +++ b/src/java/org/apache/commons/math/MessagesResources_fr.java @@ -47,6 +47,8 @@ public class MessagesResources_fr // org.apache.commons.math.util.MathUtils { "overflow: gcd({0}, {1}) is 2^31", "d\u00e9passement de capacit\u00e9 : le PGCD de {0} et {1} vaut 2^31" }, + { "cannot raise an integral value to a negative power ({0}^{1})", + "impossible d''\u00e9lever une valeur enti\u00e8re \u00e0 une puissance n\u00e9gative ({0}^{1})" }, // org.apache.commons.math.FunctionEvaluationException { "evaluation failed for argument = {0}", diff --git a/src/java/org/apache/commons/math/util/MathUtils.java b/src/java/org/apache/commons/math/util/MathUtils.java index 1a8c3d3bf..4722be6af 100644 --- a/src/java/org/apache/commons/math/util/MathUtils.java +++ b/src/java/org/apache/commons/math/util/MathUtils.java @@ -18,6 +18,7 @@ package org.apache.commons.math.util; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Arrays; import org.apache.commons.math.MathRuntimeException; @@ -1246,4 +1247,204 @@ public final class MathUtils { return ret; } + /** + * Raise an int to an int power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static int pow(final int k, int e) + throws IllegalArgumentException { + + if (e < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + int result = 1; + int k2p = k; + while (e != 0) { + if ((e & 0x1) != 0) { + result *= k2p; + } + k2p *= k2p; + e = e >> 1; + } + + return result; + + } + + /** + * Raise an int to a long power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static int pow(final int k, long e) + throws IllegalArgumentException { + + if (e < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + int result = 1; + int k2p = k; + while (e != 0) { + if ((e & 0x1) != 0) { + result *= k2p; + } + k2p *= k2p; + e = e >> 1; + } + + return result; + + } + + /** + * Raise a long to an int power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static long pow(final long k, int e) + throws IllegalArgumentException { + + if (e < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + long result = 1l; + long k2p = k; + while (e != 0) { + if ((e & 0x1) != 0) { + result *= k2p; + } + k2p *= k2p; + e = e >> 1; + } + + return result; + + } + + /** + * Raise a long to a long power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static long pow(final long k, long e) + throws IllegalArgumentException { + + if (e < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + long result = 1l; + long k2p = k; + while (e != 0) { + if ((e & 0x1) != 0) { + result *= k2p; + } + k2p *= k2p; + e = e >> 1; + } + + return result; + + } + + /** + * Raise a BigInteger to an int power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static BigInteger pow(final BigInteger k, int e) + throws IllegalArgumentException { + + if (e < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + return k.pow(e); + + } + + /** + * Raise a BigInteger to a long power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static BigInteger pow(final BigInteger k, long e) + throws IllegalArgumentException { + + if (e < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + BigInteger result = BigInteger.ONE; + BigInteger k2p = k; + while (e != 0) { + if ((e & 0x1) != 0) { + result = result.multiply(k2p); + } + k2p = k2p.multiply(k2p); + e = e >> 1; + } + + return result; + + } + + /** + * Raise a BigInteger to a BigInteger power. + * @param k number to raise + * @param e exponent (must be positive or null) + * @return ke + * @exception IllegalArgumentException if e is negative + */ + public static BigInteger pow(final BigInteger k, BigInteger e) + throws IllegalArgumentException { + + if (e.compareTo(BigInteger.ZERO) < 0) { + throw MathRuntimeException.createIllegalArgumentException( + "cannot raise an integral value to a negative power ({0}^{1})", + k, e); + } + + BigInteger result = BigInteger.ONE; + BigInteger k2p = k; + while (!BigInteger.ZERO.equals(e)) { + if (e.testBit(0)) { + result = result.multiply(k2p); + } + k2p = k2p.multiply(k2p); + e = e.shiftRight(1); + } + + return result; + + } + } diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index 6569346bf..1ec1312e5 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -39,6 +39,9 @@ The type attribute can be add,update,fix,remove. + + Added some utility functions to compute powers with integral types (int, long, BigInteger). + Fixed a comparison error when two different fractions evaluate to the same double due to limited precision. diff --git a/src/test/org/apache/commons/math/util/MathUtilsTest.java b/src/test/org/apache/commons/math/util/MathUtilsTest.java index ef354f353..392c6e177 100644 --- a/src/test/org/apache/commons/math/util/MathUtilsTest.java +++ b/src/test/org/apache/commons/math/util/MathUtilsTest.java @@ -14,6 +14,7 @@ package org.apache.commons.math.util; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -1077,4 +1078,80 @@ public final class MathUtilsTest extends TestCase { } } + + public void testPow() { + + assertEquals(1801088541, MathUtils.pow(21, 7)); + assertEquals(1, MathUtils.pow(21, 0)); + try { + MathUtils.pow(21, -7); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + assertEquals(1801088541, MathUtils.pow(21, 7l)); + assertEquals(1, MathUtils.pow(21, 0l)); + try { + MathUtils.pow(21, -7l); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + assertEquals(1801088541l, MathUtils.pow(21l, 7)); + assertEquals(1l, MathUtils.pow(21l, 0)); + try { + MathUtils.pow(21l, -7); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + assertEquals(1801088541l, MathUtils.pow(21l, 7l)); + assertEquals(1l, MathUtils.pow(21l, 0l)); + try { + MathUtils.pow(21l, -7l); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + BigInteger twentyOne = BigInteger.valueOf(21l); + assertEquals(BigInteger.valueOf(1801088541l), MathUtils.pow(twentyOne, 7)); + assertEquals(BigInteger.ONE, MathUtils.pow(twentyOne, 0)); + try { + MathUtils.pow(twentyOne, -7); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + assertEquals(BigInteger.valueOf(1801088541l), MathUtils.pow(twentyOne, 7l)); + assertEquals(BigInteger.ONE, MathUtils.pow(twentyOne, 0l)); + try { + MathUtils.pow(twentyOne, -7l); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + assertEquals(BigInteger.valueOf(1801088541l), MathUtils.pow(twentyOne, BigInteger.valueOf(7l))); + assertEquals(BigInteger.ONE, MathUtils.pow(twentyOne, BigInteger.ZERO)); + try { + MathUtils.pow(twentyOne, BigInteger.valueOf(-7l)); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected behavior + } + + BigInteger bigOne = + new BigInteger("1543786922199448028351389769265814882661837148" + + "4763915343722775611762713982220306372888519211" + + "560905579993523402015636025177602059044911261"); + assertEquals(bigOne, MathUtils.pow(twentyOne, 103)); + assertEquals(bigOne, MathUtils.pow(twentyOne, 103l)); + assertEquals(bigOne, MathUtils.pow(twentyOne, BigInteger.valueOf(103l))); + + } } \ No newline at end of file