Author: psteitz
Date: Mon Jan 19 11:43:01 2009
New Revision: 735781
URL: http://svn.apache.org/viewvc?rev=735781&view=rev
Log:
Fixed error in factorial accuracy. JIRA: MATH-240.
Modified:
commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
commons/proper/math/trunk/src/site/xdoc/changes.xml
commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
Modified:
commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java?rev=735781&r1=735780&r2=735781&view=diff
==============================================================================
---
commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
(original)
+++
commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
Mon Jan 19 11:43:01 2009
@@ -311,6 +311,13 @@
}
return true;
}
+
+ /** All long-representable factorials */
+ private static final long[] factorials = new long[]
+ {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800,
+ 479001600, 6227020800l, 87178291200l, 1307674368000l, 20922789888000l,
+ 355687428096000l, 6402373705728000l, 121645100408832000l,
+ 2432902008176640000l};
/**
* Returns n!. Shorthand for <code>n</code> <a
@@ -335,12 +342,14 @@
* @throws IllegalArgumentException if n < 0
*/
public static long factorial(final int n) {
- long result = Math.round(factorialDouble(n));
- if (result == Long.MAX_VALUE) {
+ if (n < 0) {
+ throw new IllegalArgumentException("must have n >= 0 for n!");
+ }
+ if (n > 20) {
throw new ArithmeticException(
- "result too large to represent in a long integer");
+ "factorial value is too large to fit in a long");
}
- return result;
+ return factorials[n];
}
/**
@@ -367,6 +376,9 @@
if (n < 0) {
throw new IllegalArgumentException("must have n >= 0 for n!");
}
+ if (n < 21) {
+ return factorial(n);
+ }
return Math.floor(Math.exp(factorialLog(n)) + 0.5);
}
@@ -387,6 +399,9 @@
if (n < 0) {
throw new IllegalArgumentException("must have n > 0 for n!");
}
+ if (n < 21) {
+ return Math.log(factorial(n));
+ }
double logSum = 0;
for (int i = 2; i <= n; i++) {
logSum += Math.log((double)i);
Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=735781&r1=735780&r2=735781&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Mon Jan 19 11:43:01 2009
@@ -39,6 +39,9 @@
</properties>
<body>
<release version="2.0" date="TBD" description="TBD">
+ <action dev="psteitz" type="fix" issue="MATH-240" due-to="Christian
Semrau">
+ Fixed error in factorial computation for 17 <= n <= 20.
+ </action>
<action dev="luc" type="update" >
Integration algorithms now can have both relative and absolute
accuracy settings.
@@ -49,7 +52,7 @@
<action dev="luc" type="update" >
The analysis package has been reorganized with several sub-packages.
</action>
- <action dev="luc" type="fix" issue="MATH-238" due-to="Chritian Semrau">
+ <action dev="luc" type="fix" issue="MATH-238" due-to="Christian Semrau">
Fixed an error in gcd computation for large values.
</action>
<action dev="luc" type="add" >
Modified:
commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java?rev=735781&r1=735780&r2=735781&view=diff
==============================================================================
---
commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
(original)
+++
commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
Mon Jan 19 11:43:01 2009
@@ -232,11 +232,12 @@
}
public void testFactorial() {
- for (int i = 1; i < 10; i++) {
+ for (int i = 1; i < 21; i++) {
assertEquals(i + "! ", factorial(i), MathUtils.factorial(i));
assertEquals(i + "! ", (double)factorial(i),
MathUtils.factorialDouble(i), Double.MIN_VALUE);
assertEquals(i + "! ", Math.log((double)factorial(i)),
MathUtils.factorialLog(i), 10E-12);
}
+
assertEquals("0", 1, MathUtils.factorial(0));
assertEquals("0", 1.0d, MathUtils.factorialDouble(0), 1E-14);
assertEquals("0", 0.0d, MathUtils.factorialLog(0), 1E-14);