Fixed error in factorial accuracy. JIRA: MATH-240.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@735781 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Phil Steitz 2009-01-19 19:43:01 +00:00
parent 89db6968bc
commit e4886c0a39
3 changed files with 26 additions and 7 deletions

View File

@ -312,6 +312,13 @@ public final class MathUtils {
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
* href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
@ -335,12 +342,14 @@ public final class MathUtils {
* @throws IllegalArgumentException if n < 0
*/
public static long factorial(final int n) {
long result = Math.round(factorialDouble(n));
if (result == Long.MAX_VALUE) {
throw new ArithmeticException(
"result too large to represent in a long integer");
if (n < 0) {
throw new IllegalArgumentException("must have n >= 0 for n!");
}
return result;
if (n > 20) {
throw new ArithmeticException(
"factorial value is too large to fit in a long");
}
return factorials[n];
}
/**
@ -367,6 +376,9 @@ public final class MathUtils {
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 @@ public final class MathUtils {
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);

View File

@ -39,6 +39,9 @@ The <action> type attribute can be add,update,fix,remove.
</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 @@ The <action> type attribute can be add,update,fix,remove.
<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" >

View File

@ -232,11 +232,12 @@ public final class MathUtilsTest extends TestCase {
}
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);