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;
|
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
|
* Returns n!. Shorthand for <code>n</code> <a
|
||||||
* href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
|
* href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
|
||||||
|
@ -335,12 +342,14 @@ public final class MathUtils {
|
||||||
* @throws IllegalArgumentException if n < 0
|
* @throws IllegalArgumentException if n < 0
|
||||||
*/
|
*/
|
||||||
public static long factorial(final int n) {
|
public static long factorial(final int n) {
|
||||||
long result = Math.round(factorialDouble(n));
|
if (n < 0) {
|
||||||
if (result == Long.MAX_VALUE) {
|
throw new IllegalArgumentException("must have n >= 0 for n!");
|
||||||
throw new ArithmeticException(
|
|
||||||
"result too large to represent in a long integer");
|
|
||||||
}
|
}
|
||||||
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) {
|
if (n < 0) {
|
||||||
throw new IllegalArgumentException("must have n >= 0 for n!");
|
throw new IllegalArgumentException("must have n >= 0 for n!");
|
||||||
}
|
}
|
||||||
|
if (n < 21) {
|
||||||
|
return factorial(n);
|
||||||
|
}
|
||||||
return Math.floor(Math.exp(factorialLog(n)) + 0.5);
|
return Math.floor(Math.exp(factorialLog(n)) + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +399,9 @@ public final class MathUtils {
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
throw new IllegalArgumentException("must have n > 0 for n!");
|
throw new IllegalArgumentException("must have n > 0 for n!");
|
||||||
}
|
}
|
||||||
|
if (n < 21) {
|
||||||
|
return Math.log(factorial(n));
|
||||||
|
}
|
||||||
double logSum = 0;
|
double logSum = 0;
|
||||||
for (int i = 2; i <= n; i++) {
|
for (int i = 2; i <= n; i++) {
|
||||||
logSum += Math.log((double)i);
|
logSum += Math.log((double)i);
|
||||||
|
|
|
@ -39,6 +39,9 @@ The <action> type attribute can be add,update,fix,remove.
|
||||||
</properties>
|
</properties>
|
||||||
<body>
|
<body>
|
||||||
<release version="2.0" date="TBD" description="TBD">
|
<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" >
|
<action dev="luc" type="update" >
|
||||||
Integration algorithms now can have both relative and absolute
|
Integration algorithms now can have both relative and absolute
|
||||||
accuracy settings.
|
accuracy settings.
|
||||||
|
@ -49,7 +52,7 @@ The <action> type attribute can be add,update,fix,remove.
|
||||||
<action dev="luc" type="update" >
|
<action dev="luc" type="update" >
|
||||||
The analysis package has been reorganized with several sub-packages.
|
The analysis package has been reorganized with several sub-packages.
|
||||||
</action>
|
</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.
|
Fixed an error in gcd computation for large values.
|
||||||
</action>
|
</action>
|
||||||
<action dev="luc" type="add" >
|
<action dev="luc" type="add" >
|
||||||
|
|
|
@ -232,11 +232,12 @@ public final class MathUtilsTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFactorial() {
|
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 + "! ", factorial(i), MathUtils.factorial(i));
|
||||||
assertEquals(i + "! ", (double)factorial(i), MathUtils.factorialDouble(i), Double.MIN_VALUE);
|
assertEquals(i + "! ", (double)factorial(i), MathUtils.factorialDouble(i), Double.MIN_VALUE);
|
||||||
assertEquals(i + "! ", Math.log((double)factorial(i)), MathUtils.factorialLog(i), 10E-12);
|
assertEquals(i + "! ", Math.log((double)factorial(i)), MathUtils.factorialLog(i), 10E-12);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals("0", 1, MathUtils.factorial(0));
|
assertEquals("0", 1, MathUtils.factorial(0));
|
||||||
assertEquals("0", 1.0d, MathUtils.factorialDouble(0), 1E-14);
|
assertEquals("0", 1.0d, MathUtils.factorialDouble(0), 1E-14);
|
||||||
assertEquals("0", 0.0d, MathUtils.factorialLog(0), 1E-14);
|
assertEquals("0", 0.0d, MathUtils.factorialLog(0), 1E-14);
|
||||||
|
|
Loading…
Reference in New Issue