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:
parent
89db6968bc
commit
e4886c0a39
|
@ -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);
|
||||
|
|
|
@ -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" >
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue