diff --git a/src/java/org/apache/commons/math/complex/Complex.java b/src/java/org/apache/commons/math/complex/Complex.java index f5427dab4..c138fbb21 100644 --- a/src/java/org/apache/commons/math/complex/Complex.java +++ b/src/java/org/apache/commons/math/complex/Complex.java @@ -66,7 +66,19 @@ public class Complex implements Serializable { if (isNaN()) { return Double.NaN; } - return Math.sqrt(squareSum()); + if (Math.abs(real) < Math.abs(imaginary)) { + if (imaginary == 0.0) { + return Math.abs(real); + } + double q = real / imaginary; + return (Math.abs(imaginary) * Math.sqrt(1 + q*q)); + } else { + if (real == 0.0) { + return Math.abs(imaginary); + } + double q = imaginary / real; + return (Math.abs(real) * Math.sqrt(1 + q*q)); + } } /** @@ -108,17 +120,29 @@ public class Complex implements Serializable { if (isNaN() || rhs.isNaN()) { return NaN; } - - if (Math.abs(rhs.getReal()) < Math.abs(rhs.getImaginary())) { - double q = rhs.getReal() / rhs.getImaginary(); - double d = (rhs.getReal() * q) + rhs.getImaginary(); - return new Complex(((real * q) + imaginary) / d, - ((imaginary * q) - real) / d); + + double c = rhs.getReal(); + double d = rhs.getImaginary(); + if (c == 0.0 && d == 0.0) { + throw new ArithmeticException("Error: division by zero."); + } + + if (Math.abs(c) < Math.abs(d)) { + if (d == 0.0) { + return new Complex(real/c, imaginary/c); + } + double q = c / d; + double denominator = c * q + d; + return new Complex((real * q + imaginary) / denominator, + (imaginary * q - real) / denominator); } else { - double q = rhs.getImaginary() / rhs.getReal(); - double d = (rhs.getImaginary() * q) + rhs.getReal(); - return new Complex(((imaginary * q) + real) / d, - (imaginary - (real * q)) / d); + if (c == 0.0) { + return new Complex(imaginary/d, -real/c); + } + double q = d / c; + double denominator = d * q + c; + return new Complex((imaginary * q + real) / denominator, + (imaginary - real * q) / denominator); } } @@ -215,15 +239,6 @@ public class Complex implements Serializable { return new Complex(-real, -imaginary); } - /** - * Return the sum of the squared terms. - * - * @return the square sum. - */ - private double squareSum() { - return real * real + imaginary * imaginary; - } - /** * Return the difference between this complex number and the given complex * number. diff --git a/src/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java b/src/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java index ab8cbab34..61ae1e3c2 100644 --- a/src/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java +++ b/src/java/org/apache/commons/math/distribution/HypergeometricDistributionImpl.java @@ -18,7 +18,6 @@ package org.apache.commons.math.distribution; import java.io.Serializable; -import org.apache.commons.math.MathException; import org.apache.commons.math.util.MathUtils; /** @@ -54,7 +53,8 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution super(); if (numberOfSuccesses > populationSize) { throw new IllegalArgumentException( - "number of successes must be less than or equal to population size"); + "number of successes must be less than or equal to " + + "population size"); } if (sampleSize > populationSize) { throw new IllegalArgumentException( @@ -69,10 +69,8 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution * For this disbution, X, this method returns P(X ≤ x). * @param x the value at which the PDF is evaluated. * @return PDF for this distribution. - * @throws MathException if the cumulative probability can not be - * computed due to convergence or other numerical errors. */ - public double cumulativeProbability(int x) throws MathException{ + public double cumulativeProbability(int x) { double ret; int n = getPopulationSize(); @@ -84,11 +82,10 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution ret = 0.0; } else if(x >= domain[1]) { ret = 1.0; + } else if (x - domain[0] < domain[1] - x) { + ret = lowerCumulativeProbability(domain[0], x, n, m, k); } else { - ret = 0.0; - for (int i = domain[0]; i <= x; ++i){ - ret += probability(n, m, k, i); - } + ret = 1.0 - upperCumulativeProbability(x + 1, domain[1], n, m, k); } return ret; @@ -181,6 +178,28 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution return Math.min(k, m); } + /** + * For this disbution, X, this method returns P(x0 ≤ X ≤ x1). This + * probability is computed by summing the point probabilities for the values + * x0, x0 + 1, x0 + 2, ..., x1, in that order. + * @param x0 the inclusive, lower bound + * @param x1 the inclusive, upper bound + * @param n the population size. + * @param m number of successes in the population. + * @param k the sample size. + * @return P(x0 ≤ X ≤ x1). + */ + private double lowerCumulativeProbability( + int x0, int x1, int n, int m, int k) + { + double ret; + ret = 0.0; + for (int i = x0; i <= x1; ++i) { + ret += probability(n, m, k, i); + } + return ret; + } + /** * For this disbution, X, this method returns P(X = x). * @@ -203,7 +222,7 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution return ret; } - + /** * For the disbution, X, defined by the given hypergeometric distribution * parameters, this method returns P(X = x). @@ -219,7 +238,7 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution MathUtils.binomialCoefficientLog(n - m, k - x) - MathUtils.binomialCoefficientLog(n, k)); } - + /** * Modify the number of successes. * @param num the new number of successes. @@ -245,8 +264,8 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution } populationSize = size; } - - /** + + /** * Modify the sample size. * @param size the new sample size. * @throws IllegalArgumentException if size is negative. @@ -258,4 +277,52 @@ public class HypergeometricDistributionImpl extends AbstractIntegerDistribution } sampleSize = size; } + + /** + * For this disbution, X, this method returns P(X ≥ x). + * @param x the value at which the CDF is evaluated. + * @return upper tail CDF for this distribution. + */ + public double upperCumulativeProbability(int x) { + double ret; + + int n = getPopulationSize(); + int m = getNumberOfSuccesses(); + int k = getSampleSize(); + + int[] domain = getDomain(n, m, k); + if (x < domain[0]) { + ret = 1.0; + } else if(x >= domain[1]) { + ret = 0.0; + } else if (x - domain[0] < domain[1] - x) { + ret = 1.0 - lowerCumulativeProbability(domain[0], x - 1, n, m, k); + } else { + ret = upperCumulativeProbability(x, domain[1], n, m, k); + } + + return ret; + } + + /** + * For this disbution, X, this method returns P(x0 ≤ X ≤ x1). This + * probability is computed by summing the point probabilities for the values + * x1, x1 - 1, x1 - 2, ..., x0, in that order. + * @param x0 the inclusive, lower bound + * @param x1 the inclusive, upper bound + * @param n the population size. + * @param m number of successes in the population. + * @param k the sample size. + * @return P(x0 ≤ X ≤ x1). + */ + private double upperCumulativeProbability( + int x0, int x1, int n, int m, int k) + { + double ret = 0.0; + for (int i = x1; i >= x0; --i) { + ret += probability(n, m, k, i); + } + return ret; + } + } diff --git a/src/java/org/apache/commons/math/special/Gamma.java b/src/java/org/apache/commons/math/special/Gamma.java index 19c389478..633715af2 100644 --- a/src/java/org/apache/commons/math/special/Gamma.java +++ b/src/java/org/apache/commons/math/special/Gamma.java @@ -155,7 +155,7 @@ public class Gamma implements Serializable { ret = Double.NaN; } else if (x == 0.0) { ret = 0.0; - } else if (a > 1.0 && x > a) { + } else if (a >= 1.0 && x > a) { // use regularizedGammaQ because it should converge faster in this // case. ret = 1.0 - regularizedGammaQ(a, x, epsilon, maxIterations); @@ -231,7 +231,7 @@ public class Gamma implements Serializable { ret = Double.NaN; } else if (x == 0.0) { ret = 1.0; - } else if (x < a || a <= 1.0) { + } else if (x < a || a < 1.0) { // use regularizedGammaP because it should converge faster in this // case. ret = 1.0 - regularizedGammaP(a, x, epsilon, maxIterations); diff --git a/src/java/org/apache/commons/math/stat/StatUtils.java b/src/java/org/apache/commons/math/stat/StatUtils.java index 2c040b2c2..1ea14b5d7 100644 --- a/src/java/org/apache/commons/math/stat/StatUtils.java +++ b/src/java/org/apache/commons/math/stat/StatUtils.java @@ -604,8 +604,8 @@ public final class StatUtils { double sum2 = 0d; double diff = 0d; int n = sample1.length; - if (n < 2) { - throw new IllegalArgumentException("Input array lengths must be at least 2."); + if (n < 2 || n != sample2.length) { + throw new IllegalArgumentException("Input array lengths must be equal and at least 2."); } for (int i = 0; i < n; i++) { diff = sample1[i] - sample2[i]; diff --git a/src/java/org/apache/commons/math/util/ContinuedFraction.java b/src/java/org/apache/commons/math/util/ContinuedFraction.java index 2c630876e..5804d95be 100644 --- a/src/java/org/apache/commons/math/util/ContinuedFraction.java +++ b/src/java/org/apache/commons/math/util/ContinuedFraction.java @@ -100,16 +100,25 @@ public abstract class ContinuedFraction implements Serializable { } /** + *

* Evaluates the continued fraction at the value x. + *

* - * The implementation of this method is based on: + *

+ * The implementation of this method is based on equations 14-17 of: *

- * + * The recurrence relationship defined in those equations can result in + * very large intermediate results which can result in numerical overflow. + * As a means to combat these overflow conditions, the intermediate results + * are scaled whenever they threaten to become numerically unstable. + * * @param x the evaluation point. * @param epsilon maximum error allowed. * @param maxIterations maximum number of convergents @@ -119,72 +128,50 @@ public abstract class ContinuedFraction implements Serializable { public double evaluate(double x, double epsilon, int maxIterations) throws MathException { - double[][] f = new double[2][2]; - double[][] a = new double[2][2]; - double[][] an = new double[2][2]; + double p0 = 1.0; + double p1 = getA(0, x); + double q0 = 0.0; + double q1 = 1.0; + double c = p1 / q1; + int n = 0; + double relativeError = Double.MAX_VALUE; + while (n < maxIterations && relativeError > epsilon) { + ++n; + double a = getA(n, x); + double b = getB(n, x); + double p2 = a * p1 + b * p0; + double q2 = a * q1 + b * q0; + if (Double.isInfinite(p2) || Double.isInfinite(q2)) { + // need to scale + if (a != 0.0) { + p2 = p1 + (b / a * p0); + q2 = q1 + (b / a * q0); + } else if (b != 0) { + p2 = (a / b * p1) + p0; + q2 = (a / b * q1) + q0; + } else { + // can not scale an convergent is unbounded. + throw new ConvergenceException( + "Continued fraction convergents diverged to +/- " + + "infinity."); + } + } + double r = p2 / q2; + relativeError = Math.abs(r / c - 1.0); + + // prepare for next iteration + c = p2 / q2; + p0 = p1; + p1 = p2; + q0 = q1; + q1 = q2; + } - a[0][0] = getA(0, x); - a[0][1] = 1.0; - a[1][0] = 1.0; - a[1][1] = 0.0; - - return evaluate(1, x, a, an, f, epsilon, maxIterations); - } - - /** - * Evaluates the n-th convergent, fn = pn / qn, for this continued fraction - * at the value x. - * @param n the convergent to compute. - * @param x the evaluation point. - * @param a (n-1)-th convergent matrix. (Input) - * @param an the n-th coefficient matrix. (Output) - * @param f the n-th convergent matrix. (Output) - * @param epsilon maximum error allowed. - * @param maxIterations maximum number of convergents - * @return the value of the the n-th convergent for this continued fraction - * evaluated at x. - * @throws MathException if the algorithm fails to converge. - */ - private double evaluate( - int n, - double x, - double[][] a, - double[][] an, - double[][] f, - double epsilon, - int maxIterations) throws MathException - { - double ret; - - // create next matrix - an[0][0] = getA(n, x); - an[0][1] = 1.0; - an[1][0] = getB(n, x); - an[1][1] = 0.0; - - // multiply a and an, save as f - f[0][0] = (a[0][0] * an[0][0]) + (a[0][1] * an[1][0]); - f[0][1] = (a[0][0] * an[0][1]) + (a[0][1] * an[1][1]); - f[1][0] = (a[1][0] * an[0][0]) + (a[1][1] * an[1][0]); - f[1][1] = (a[1][0] * an[0][1]) + (a[1][1] * an[1][1]); - - // determine if we're close enough - if (Math.abs((f[0][0] * f[1][1]) - (f[1][0] * f[0][1])) < - Math.abs(epsilon * f[1][0] * f[1][1])) - { - ret = f[0][0] / f[1][0]; - } else { - if (n >= maxIterations) { - throw new ConvergenceException( - "Continued fraction convergents failed to converge."); - } - // compute next - ret = evaluate(n + 1, x, f /* new a */ - , an /* reuse an */ - , a /* new f */ - , epsilon, maxIterations); + if (n >= maxIterations) { + throw new ConvergenceException( + "Continued fraction convergents failed to converge."); } - return ret; + return c; } } diff --git a/src/java/org/apache/commons/math/util/MathUtils.java b/src/java/org/apache/commons/math/util/MathUtils.java index 6aba55638..c4cfb0740 100644 --- a/src/java/org/apache/commons/math/util/MathUtils.java +++ b/src/java/org/apache/commons/math/util/MathUtils.java @@ -1,12 +1,17 @@ /* - * Copyright 2003-2005 The Apache Software Foundation. Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright 2003-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.apache.commons.math.util; @@ -15,9 +20,7 @@ import java.math.BigDecimal; /** * Some useful additions to the built-in functions in {@link Math}. - * - * @version $Revision$ $Date: 2005-07-30 02:25:26 -0500 (Sat, 30 Jul - * 2005) $ + * @version $Revision$ $Date$ */ public final class MathUtils { @@ -496,7 +499,7 @@ public final class MathUtils { * @since 1.1 */ public static double round(double x, int scale, int roundingMethod) { - double sign = sign(x); + double sign = indicator(x); double factor = Math.pow(10.0, scale) * sign; return roundUnscaled(x * factor, sign, roundingMethod) / factor; } @@ -527,7 +530,7 @@ public final class MathUtils { * @since 1.1 */ public static float round(float x, int scale, int roundingMethod) { - float sign = sign(x); + float sign = indicator(x); float factor = (float)Math.pow(10.0f, scale) * sign; return (float)roundUnscaled(x * factor, sign, roundingMethod) / factor; } diff --git a/src/test/org/apache/commons/math/distribution/PoissonDistributionTest.java b/src/test/org/apache/commons/math/distribution/PoissonDistributionTest.java index 88df7f497..8cf79aeab 100644 --- a/src/test/org/apache/commons/math/distribution/PoissonDistributionTest.java +++ b/src/test/org/apache/commons/math/distribution/PoissonDistributionTest.java @@ -15,6 +15,8 @@ */ package org.apache.commons.math.distribution; +import org.apache.commons.math.MathException; + /** * PoissonDistributionTest * @@ -133,4 +135,46 @@ public class PoissonDistributionTest extends IntegerDistributionAbstractTest { dist.setMean(10.0); assertEquals(10.0, dist.getMean(), 0.0); } + + public void testLargeMeanCumulativeProbability() { + PoissonDistribution dist = DistributionFactory.newInstance().createPoissonDistribution(1.0); + double mean = 1.0; + while (mean <= 10000000.0) { + dist.setMean(mean); + + double x = mean * 2.0; + double dx = x / 10.0; + while (x >= 0) { + try { + dist.cumulativeProbability(x); + } catch (MathException ex) { + fail("mean of " + mean + " and x of " + x + " caused " + ex.getMessage()); + } + x -= dx; + } + + mean *= 10.0; + } + } + + public void testLargeMeanInverseCumulativeProbability() { + PoissonDistribution dist = DistributionFactory.newInstance().createPoissonDistribution(1.0); + double mean = 1.0; + while (mean <= 10000000.0) { + dist.setMean(mean); + + double p = 0.1; + double dp = p; + while (p < 1.0) { + try { + dist.inverseCumulativeProbability(p); + } catch (MathException ex) { + fail("mean of " + mean + " and p of " + p + " caused " + ex.getMessage()); + } + p += dp; + } + + mean *= 10.0; + } + } } \ No newline at end of file diff --git a/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java b/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java index 0a4293ea5..d37b21878 100644 --- a/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java +++ b/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java @@ -422,6 +422,11 @@ public final class RealMatrixImplTest extends TestCase { RealMatrix lu = m.getLUMatrix(); assertClose("LU decomposition", lu, (RealMatrix) new RealMatrixImpl(testDataLU), normTolerance); verifyDecomposition(m, lu); + // access LU decomposition on same object to verify caching. + lu = m.getLUMatrix(); + assertClose("LU decomposition", lu, (RealMatrix) new RealMatrixImpl(testDataLU), normTolerance); + verifyDecomposition(m, lu); + m = new RealMatrixImpl(luData); lu = m.getLUMatrix(); assertClose("LU decomposition", lu, (RealMatrix) new RealMatrixImpl(luDataLUDecomposition), normTolerance); @@ -642,6 +647,19 @@ public final class RealMatrixImplTest extends TestCase { } catch (MatrixIndexException e) { // expected } + // dimension underflow + try { + m.setSubMatrix(testData,-1,1); + fail("expecting MatrixIndexException"); + } catch (MatrixIndexException e) { + // expected + } + try { + m.setSubMatrix(testData,1,-1); + fail("expecting MatrixIndexException"); + } catch (MatrixIndexException e) { + // expected + } // null try { diff --git a/src/test/org/apache/commons/math/stat/FrequencyTest.java b/src/test/org/apache/commons/math/stat/FrequencyTest.java index 4e5893de7..4d11e93fd 100644 --- a/src/test/org/apache/commons/math/stat/FrequencyTest.java +++ b/src/test/org/apache/commons/math/stat/FrequencyTest.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.io.StringReader; import java.util.Iterator; +import org.apache.commons.math.TestUtils; + import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -111,6 +113,21 @@ public final class FrequencyTest extends TestCase { assertEquals("one count", 3 , f.getCount("one")); assertEquals("Z cumulative pct -- case insensitive", 1 , f.getCumPct("Z"), tolerance); assertEquals("z cumulative pct -- case insensitive", 1 , f.getCumPct("z"), tolerance); + + f = null; + f = new Frequency(); + assertEquals(0L, f.getCount('a')); + assertEquals(0L, f.getCumFreq('b')); + TestUtils.assertEquals(Double.NaN, f.getPct('a'), 0.0); + TestUtils.assertEquals(Double.NaN, f.getCumPct('b'), 0.0); + f.addValue('a'); + f.addValue('b'); + f.addValue('c'); + f.addValue('d'); + assertEquals(1L, f.getCount('a')); + assertEquals(2L, f.getCumFreq('b')); + assertEquals(0.25, f.getPct('a'), 0.0); + assertEquals(0.5, f.getCumPct('b'), 0.0); } /** test pcts */ diff --git a/src/test/org/apache/commons/math/stat/StatUtilsTest.java b/src/test/org/apache/commons/math/stat/StatUtilsTest.java index 11f6b661a..2e1143c8d 100644 --- a/src/test/org/apache/commons/math/stat/StatUtilsTest.java +++ b/src/test/org/apache/commons/math/stat/StatUtilsTest.java @@ -371,6 +371,19 @@ public final class StatUtilsTest extends TestCase { } catch (IllegalArgumentException ex) { // expected } + try { + StatUtils.varianceDifference(sample1, small, meanDifference); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + try { + double[] single = {1.0}; + StatUtils.varianceDifference(single, single, meanDifference); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } } public void testGeometricMean() throws Exception { @@ -384,5 +397,7 @@ public final class StatUtilsTest extends TestCase { test = new double[] {2, 4, 6, 8}; assertEquals(Math.exp(0.25d * StatUtils.sumLog(test)), StatUtils.geometricMean(test), Double.MIN_VALUE); + assertEquals(Math.exp(0.5 * StatUtils.sumLog(test, 0, 2)), + StatUtils.geometricMean(test, 0, 2), Double.MIN_VALUE); } } \ No newline at end of file diff --git a/src/test/org/apache/commons/math/stat/descriptive/rank/PercentileTest.java b/src/test/org/apache/commons/math/stat/descriptive/rank/PercentileTest.java index 3381a2468..59e836428 100644 --- a/src/test/org/apache/commons/math/stat/descriptive/rank/PercentileTest.java +++ b/src/test/org/apache/commons/math/stat/descriptive/rank/PercentileTest.java @@ -72,6 +72,20 @@ public class PercentileTest extends UnivariateStatisticAbstractTest{ assertEquals(3.75, p.evaluate(d), 1.0e-5); p.setQuantile(50); assertEquals(2.5, p.evaluate(d), 1.0e-5); + + // invalid percentiles + try { + p.evaluate(d, 0, d.length, -1.0); + fail(); + } catch (IllegalArgumentException ex) { + // success + } + try { + p.evaluate(d, 0, d.length, 101.0); + fail(); + } catch (IllegalArgumentException ex) { + // success + } } public void testNISTExample() { diff --git a/src/test/org/apache/commons/math/util/MathUtilsTest.java b/src/test/org/apache/commons/math/util/MathUtilsTest.java index 563a94833..18220daad 100644 --- a/src/test/org/apache/commons/math/util/MathUtilsTest.java +++ b/src/test/org/apache/commons/math/util/MathUtilsTest.java @@ -17,6 +17,8 @@ package org.apache.commons.math.util; import java.math.BigDecimal; +import org.apache.commons.math.TestUtils; + import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -556,6 +558,12 @@ public final class MathUtilsTest extends TestCase { } catch (IllegalArgumentException ex) { // success } + + // special values + TestUtils.assertEquals(Float.NaN, MathUtils.round(Float.NaN, 2), 0.0f); + assertEquals(0.0f, MathUtils.round(0.0f, 2), 0.0f); + assertEquals(Float.POSITIVE_INFINITY, MathUtils.round(Float.POSITIVE_INFINITY, 2), 0.0f); + assertEquals(Float.NEGATIVE_INFINITY, MathUtils.round(Float.NEGATIVE_INFINITY, 2), 0.0f); } public void testRoundDouble() { @@ -646,5 +654,11 @@ public final class MathUtilsTest extends TestCase { } catch (IllegalArgumentException ex) { // success } + + // special values + TestUtils.assertEquals(Double.NaN, MathUtils.round(Double.NaN, 2), 0.0); + assertEquals(0.0, MathUtils.round(0.0, 2), 0.0); + assertEquals(Double.POSITIVE_INFINITY, MathUtils.round(Double.POSITIVE_INFINITY, 2), 0.0); + assertEquals(Double.NEGATIVE_INFINITY, MathUtils.round(Double.NEGATIVE_INFINITY, 2), 0.0); } } \ No newline at end of file diff --git a/xdocs/changes.xml b/xdocs/changes.xml index 92a1f027a..8e051816b 100644 --- a/xdocs/changes.xml +++ b/xdocs/changes.xml @@ -50,6 +50,20 @@ Commons Math Release Notes and numerical utilities, and a PRNG pluggability framework making it possible to replace the JDK-supplied random number generator in commons-math (and elsewhere) with alternative PRNG implementations."> + + Fixed division by zero error in rounding methods. + + + Added upper tail cumulative probability method to HypergeometricDistributionImpl. + + + Added better handling of numerical overflow and division by zero in + Complex calculations. + + + Changed ContinuedFraction to better handle infinite convergents that + resulted in divergent continued fraction evaluations. + Changed rounding methods to not rely on BigDecimal conversions which was causing numerical error.