You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by br...@apache.org on 2007/10/31 08:23:02 UTC

svn commit: r590577 - in /commons/proper/math/trunk: src/java/org/apache/commons/math/util/MathUtils.java src/test/org/apache/commons/math/util/MathUtilsTest.java xdocs/changes.xml

Author: brentworden
Date: Wed Oct 31 00:23:01 2007
New Revision: 590577

URL: http://svn.apache.org/viewvc?rev=590577&view=rev
Log:
MATH-154. Added addAndCheck, mulAndCheck, and subAndCheck MathUtils methods for long integer arguments.

Modified:
    commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
    commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
    commons/proper/math/trunk/xdocs/changes.xml

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=590577&r1=590576&r2=590577&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 Wed Oct 31 00:23:01 2007
@@ -69,6 +69,66 @@
     }
 
     /**
+     * Add two long integers, checking for overflow.
+     * 
+     * @param a an addend
+     * @param b an addend
+     * @return the sum <code>a+b</code>
+     * @throws ArithmeticException if the result can not be represented as an
+     *         long
+     * @since 1.2
+     */
+    public static long addAndCheck(long a, long b) {
+        return addAndCheck(a, b, "overflow: add");
+    }
+    
+    /**
+     * Add two long integers, checking for overflow.
+     * 
+     * @param a an addend
+     * @param b an addend
+     * @param msg the message to use for any thrown exception.
+     * @return the sum <code>a+b</code>
+     * @throws ArithmeticException if the result can not be represented as an
+     *         long
+     * @since 1.2
+     */
+    private static long addAndCheck(long a, long b, String msg) {
+        long ret;
+        if (a > b) {
+            // use symmetry to reduce boundry cases
+            ret = addAndCheck(b, a, msg);
+        } else {
+            // assert a <= b
+            
+            if (a < 0) {
+                if (b < 0) {
+                    // check for negative overflow
+                    if (Long.MIN_VALUE - b <= a) {
+                        ret = a + b;
+                    } else {
+                        throw new ArithmeticException(msg);
+                    }
+                } else {
+                    // oppisite sign addition is always safe
+                    ret = a + b;
+                }
+            } else {
+                // assert a >= 0
+                // assert b >= 0
+
+                // check for positive overflow
+                if (a <= Long.MAX_VALUE - b) {
+                    ret = a + b;
+                } else {
+                    throw new ArithmeticException(msg);
+                }
+            }
+        }
+        return ret;
+    }
+    
+    /**
      * Returns an exact representation of the <a
      * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
      * Coefficient</a>, "<code>n choose k</code>", the number of
@@ -117,26 +177,7 @@
         }
         return result;
     }
-    
-    /** 
-     * <p>Returns the 
-     * <a href="http://mathworld.wolfram.com/Logarithm.html">logarithm</a>
-     * for base <code>b</code> of <code>x</code>.
-     * </p>
-     * <p>Returns <code>NaN<code> if either argument is negative.  If 
-     * <code>base</code> is 0 and <code>x</code> is positive, 0 is returned.
-     * If <code>base</code> is positive and <code>x</code> is 0, 
-     * <code>Double.NEGATIVE_INFINITY</code> is returned.  If both arguments
-     * are 0, the result is <code>NaN</code>.</p>
-     * 
-     * @param base the base of the logarithm, must be greater than 0
-     * @param x argument, must be greater than 0
-     * @return the value of the logarithm - the number y such that base^y = x.
-     */ 
-    public static double log(double base, double x) {
-    	return Math.log(x)/Math.log(base);
-    }
-    
+
     /**
      * Returns a <code>double</code> representation of the <a
      * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
@@ -162,7 +203,7 @@
     public static double binomialCoefficientDouble(final int n, final int k) {
         return Math.floor(Math.exp(binomialCoefficientLog(n, k)) + 0.5);
     }
-
+    
     /**
      * Returns the natural <code>log</code> of the <a
      * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
@@ -210,7 +251,7 @@
 
         return logSum;
     }
-
+    
     /**
      * Returns the <a href="http://mathworld.wolfram.com/HyperbolicCosine.html">
      * hyperbolic cosine</a> of x.
@@ -221,7 +262,7 @@
     public static double cosh(double x) {
         return (Math.exp(x) + Math.exp(-x)) / 2.0;
     }
-
+    
     /**
      * Returns true iff both arguments are NaN or neither is NaN and they are
      * equal
@@ -475,6 +516,25 @@
         return Math.abs(mulAndCheck(a / gcd(a, b), b));
     }
 
+    /** 
+     * <p>Returns the 
+     * <a href="http://mathworld.wolfram.com/Logarithm.html">logarithm</a>
+     * for base <code>b</code> of <code>x</code>.
+     * </p>
+     * <p>Returns <code>NaN<code> if either argument is negative.  If 
+     * <code>base</code> is 0 and <code>x</code> is positive, 0 is returned.
+     * If <code>base</code> is positive and <code>x</code> is 0, 
+     * <code>Double.NEGATIVE_INFINITY</code> is returned.  If both arguments
+     * are 0, the result is <code>NaN</code>.</p>
+     * 
+     * @param base the base of the logarithm, must be greater than 0
+     * @param x argument, must be greater than 0
+     * @return the value of the logarithm - the number y such that base^y = x.
+     */ 
+    public static double log(double base, double x) {
+    	return Math.log(x)/Math.log(base);
+    }
+
     /**
      * Multiply two integers, checking for overflow.
      * 
@@ -494,6 +554,61 @@
     }
 
     /**
+     * Multiply two long integers, checking for overflow.
+     * 
+     * @param a first value
+     * @param b second value
+     * @return the product <code>a * b</code>
+     * @throws ArithmeticException if the result can not be represented as an
+     *         long
+     * @since 1.2
+     */
+    public static long mulAndCheck(long a, long b) {
+        long ret;
+        String msg = "overflow: multiply";
+        if (a > b) {
+            // use symmetry to reduce boundry cases
+            ret = mulAndCheck(b, a);
+        } else {
+            if (a < 0) {
+                if (b < 0) {
+                    // check for positive overflow with negative a, negative b
+                    if (a >= Long.MAX_VALUE / b) {
+                        ret = a * b;
+                    } else {
+                        throw new ArithmeticException(msg);
+                    }
+                } else if (b > 0) {
+                    // check for negative overflow with negative a, positive b
+                    if (Long.MIN_VALUE / b <= a) {
+                        ret = a * b;
+                    } else {
+                        throw new ArithmeticException(msg);
+                        
+                    }
+                } else {
+                    // assert b == 0
+                    ret = 0;
+                }
+            } else if (a > 0) {
+                // assert a > 0
+                // assert b > 0
+                
+                // check for positive overflow with positive a, positive b
+                if (a <= Long.MAX_VALUE / b) {
+                    ret = a * b;
+                } else {
+                    throw new ArithmeticException(msg);
+                }
+            } else {
+                // assert a == 0
+                ret = 0;
+            }
+        }
+        return ret;
+    }
+
+    /**
      * Get the next machine representable number after a number, moving
      * in the direction of another number.
      * <p>
@@ -823,5 +938,31 @@
             throw new ArithmeticException("overflow: subtract");
         }
         return (int)s;
+    }
+
+    /**
+     * Subtract two long integers, checking for overflow.
+     * 
+     * @param a first value
+     * @param b second value
+     * @return the difference <code>a-b</code>
+     * @throws ArithmeticException if the result can not be represented as an
+     *         long
+     * @since 1.2
+     */
+    public static long subAndCheck(long a, long b) {
+        long ret;
+        String msg = "overflow: subtract";
+        if (b == Long.MIN_VALUE) {
+            if (a < 0) {
+                ret = a - b;
+            } else {
+                throw new ArithmeticException(msg);
+            }
+        } else {
+            // use additive inverse
+            ret = addAndCheck(a, -b, msg);
+        }
+        return ret;
     }
 }

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=590577&r1=590576&r2=590577&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 Wed Oct 31 00:23:01 2007
@@ -1,33 +1,30 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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;
 
 import java.math.BigDecimal;
 
-import org.apache.commons.math.TestUtils;
-
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
+import org.apache.commons.math.TestUtils;
+
 /**
  * Test cases for the MathUtils class.
- *
- * @version $Revision$ $Date$
+ * @version $Revision$ $Date: 2007-08-16 15:36:33 -0500 (Thu, 16 Aug
+ *          2007) $
  */
 public final class MathUtilsTest extends TestCase {
 
@@ -40,7 +37,38 @@
         suite.setName("MathUtils Tests");
         return suite;
     }
-    
+
+    /**
+     * Exact recursive implementation to test against
+     */
+    private long binomialCoefficient(int n, int k) {
+        if ((n == k) || (k == 0)) {
+            return 1;
+        }
+        if ((k == 1) || (k == n - 1)) {
+            return n;
+        }
+        return binomialCoefficient(n - 1, k - 1) + binomialCoefficient(n - 1, k);
+    }
+
+    /**
+     * Exact direct multiplication implementation to test against
+     */
+    private long factorial(int n) {
+        long result = 1;
+        for (int i = 2; i <= n; i++) {
+            result *= i;
+        }
+        return result;
+    }
+
+    /** Verify that b(0,0) = 1 */
+    public void test0Choose0() {
+        assertEquals(MathUtils.binomialCoefficientDouble(0, 0), 1d, 0);
+        assertEquals(MathUtils.binomialCoefficientLog(0, 0), 0d, 0);
+        assertEquals(MathUtils.binomialCoefficient(0, 0), 1);
+    }
+
     public void testAddAndCheck() {
         int big = Integer.MAX_VALUE;
         int bigNeg = Integer.MIN_VALUE;
@@ -48,130 +76,144 @@
         try {
             MathUtils.addAndCheck(big, 1);
             fail("Expecting ArithmeticException");
-        } catch (ArithmeticException ex) {}
+        } catch (ArithmeticException ex) {
+        }
         try {
             MathUtils.addAndCheck(bigNeg, -1);
             fail("Expecting ArithmeticException");
-        } catch (ArithmeticException ex) {}
-    }
-    
-    public void testMulAndCheck() {
-        int big = Integer.MAX_VALUE;
-        int bigNeg = Integer.MIN_VALUE;
-        assertEquals(big, MathUtils.mulAndCheck(big, 1));
-        try {
-            MathUtils.mulAndCheck(big, 2);
-            fail("Expecting ArithmeticException");
-        } catch (ArithmeticException ex) {}
-        try {
-            MathUtils.mulAndCheck(bigNeg, 2);
-            fail("Expecting ArithmeticException");
-        } catch (ArithmeticException ex) {}
+        } catch (ArithmeticException ex) {
+        }
     }
-    
-    public void testSubAndCheck() {
-        int big = Integer.MAX_VALUE;
-        int bigNeg = Integer.MIN_VALUE;
-        assertEquals(big, MathUtils.subAndCheck(big, 0));
-        try {
-            MathUtils.subAndCheck(big, -1);
-            fail("Expecting ArithmeticException");
-        } catch (ArithmeticException ex) {}
-        try {
-            MathUtils.subAndCheck(bigNeg, 1);
-            fail("Expecting ArithmeticException");
-        } catch (ArithmeticException ex) {}
+
+    public void testAddAndCheckLong() {
+        long max = Long.MAX_VALUE;
+        long min = Long.MIN_VALUE;
+        assertEquals(max, MathUtils.addAndCheck(max, 0L));
+        assertEquals(min, MathUtils.addAndCheck(min, 0L));
+        assertEquals(max, MathUtils.addAndCheck(0L, max));
+        assertEquals(min, MathUtils.addAndCheck(0L, min));
+        assertEquals(1, MathUtils.addAndCheck(-1L, 2L));
+        assertEquals(1, MathUtils.addAndCheck(2L, -1L));
+        testAddAndCheckLongFailure(max, 1L);
+        testAddAndCheckLongFailure(min, -1L);
+        testAddAndCheckLongFailure(1L, max);
+        testAddAndCheckLongFailure(-1L, min);
     }
-    
-    public void testSubAndCheckErrorMessage() {
-        int big = Integer.MAX_VALUE;
+
+    private void testAddAndCheckLongFailure(long a, long b) {
         try {
-            MathUtils.subAndCheck(big, -1);
+            MathUtils.addAndCheck(a, b);
             fail("Expecting ArithmeticException");
         } catch (ArithmeticException ex) {
-            assertEquals("overflow: subtract", ex.getMessage());
+            // success
         }
     }
-    
+
     public void testBinomialCoefficient() {
-        long[] bcoef5 = {1,5,10,10,5,1};
-        long[] bcoef6 = {1,6,15,20,15,6,1};
+        long[] bcoef5 = {
+            1,
+            5,
+            10,
+            10,
+            5,
+            1 };
+        long[] bcoef6 = {
+            1,
+            6,
+            15,
+            20,
+            15,
+            6,
+            1 };
         for (int i = 0; i < 6; i++) {
-            assertEquals("5 choose " + i, bcoef5[i], 
-                MathUtils.binomialCoefficient(5,i));
+            assertEquals("5 choose " + i, bcoef5[i], MathUtils.binomialCoefficient(5, i));
         }
         for (int i = 0; i < 7; i++) {
-            assertEquals("6 choose " + i, bcoef6[i], 
-                MathUtils.binomialCoefficient(6,i));
+            assertEquals("6 choose " + i, bcoef6[i], MathUtils.binomialCoefficient(6, i));
         }
-        
+
         for (int n = 1; n < 10; n++) {
             for (int k = 0; k <= n; k++) {
-                assertEquals(n + " choose " + k, binomialCoefficient(n, k), 
-                    MathUtils.binomialCoefficient(n, k));
-                assertEquals(n + " choose " + k,(double) binomialCoefficient(n, k), 
-                    MathUtils.binomialCoefficientDouble(n, k),Double.MIN_VALUE);
-                assertEquals(n + " choose " + k,
-                    Math.log((double) binomialCoefficient(n, k)), 
-                    MathUtils.binomialCoefficientLog(n, k),10E-12);
+                assertEquals(n + " choose " + k, binomialCoefficient(n, k), MathUtils.binomialCoefficient(n, k));
+                assertEquals(n + " choose " + k, (double)binomialCoefficient(n, k), MathUtils.binomialCoefficientDouble(n, k), Double.MIN_VALUE);
+                assertEquals(n + " choose " + k, Math.log((double)binomialCoefficient(n, k)), MathUtils.binomialCoefficientLog(n, k), 10E-12);
             }
         }
-      
-      /* 
-       * Takes a long time for recursion to unwind, but succeeds 
-       * and yields exact value = 2,333,606,220
-        
-        assertEquals(MathUtils.binomialCoefficient(34,17),
-            binomialCoefficient(34,17));
-       */
-    }
-    
-    /** Verify that b(0,0) = 1 */
-    public void test0Choose0() {
-        assertEquals(MathUtils.binomialCoefficientDouble(0, 0), 1d, 0);
-        assertEquals(MathUtils.binomialCoefficientLog(0, 0), 0d, 0);
-        assertEquals(MathUtils.binomialCoefficient(0, 0), 1);
+
+        /*
+         * Takes a long time for recursion to unwind, but succeeds and yields
+         * exact value = 2,333,606,220
+         * assertEquals(MathUtils.binomialCoefficient(34,17),
+         * binomialCoefficient(34,17));
+         */
     }
-    
+
     public void testBinomialCoefficientFail() {
         try {
-            MathUtils.binomialCoefficient(4,5);
-            fail ("expecting IllegalArgumentException");
+            MathUtils.binomialCoefficient(4, 5);
+            fail("expecting IllegalArgumentException");
         } catch (IllegalArgumentException ex) {
             ;
         }
-        
+
         try {
-            MathUtils.binomialCoefficientDouble(4,5);
-            fail ("expecting IllegalArgumentException");
+            MathUtils.binomialCoefficientDouble(4, 5);
+            fail("expecting IllegalArgumentException");
         } catch (IllegalArgumentException ex) {
             ;
         }
-        
+
         try {
-            MathUtils.binomialCoefficientLog(4,5);
-            fail ("expecting IllegalArgumentException");
+            MathUtils.binomialCoefficientLog(4, 5);
+            fail("expecting IllegalArgumentException");
         } catch (IllegalArgumentException ex) {
             ;
         }
         try {
-            MathUtils.binomialCoefficient(67,34);
-            fail ("expecting ArithmeticException");
+            MathUtils.binomialCoefficient(67, 34);
+            fail("expecting ArithmeticException");
         } catch (ArithmeticException ex) {
             ;
         }
-        double x = MathUtils.binomialCoefficientDouble(1030,515);
-        assertTrue("expecting infinite binomial coefficient",
-            Double.isInfinite(x));
+        double x = MathUtils.binomialCoefficientDouble(1030, 515);
+        assertTrue("expecting infinite binomial coefficient", Double.isInfinite(x));
+    }
+
+    public void testCosh() {
+        double x = 3.0;
+        double expected = 10.06766;
+        assertEquals(expected, MathUtils.cosh(x), 1.0e-5);
+    }
+
+    public void testCoshNaN() {
+        assertTrue(Double.isNaN(MathUtils.cosh(Double.NaN)));
+    }
+
+    public void testEquals() {
+        double[] testArray = {
+            Double.NaN,
+            Double.POSITIVE_INFINITY,
+            Double.NEGATIVE_INFINITY,
+            1d,
+            0d };
+        for (int i = 0; i < testArray.length; i++) {
+            for (int j = 0; j < testArray.length; j++) {
+                if (i == j) {
+                    assertTrue(MathUtils.equals(testArray[i], testArray[j]));
+                    assertTrue(MathUtils.equals(testArray[j], testArray[i]));
+                } else {
+                    assertTrue(!MathUtils.equals(testArray[i], testArray[j]));
+                    assertTrue(!MathUtils.equals(testArray[j], testArray[i]));
+                }
+            }
+        }
     }
 
     public void testFactorial() {
         for (int i = 1; i < 10; 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(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);
@@ -181,306 +223,121 @@
     public void testFactorialFail() {
         try {
             MathUtils.factorial(-1);
-            fail ("expecting IllegalArgumentException");
+            fail("expecting IllegalArgumentException");
         } catch (IllegalArgumentException ex) {
             ;
         }
         try {
             MathUtils.factorialDouble(-1);
-            fail ("expecting IllegalArgumentException");
+            fail("expecting IllegalArgumentException");
         } catch (IllegalArgumentException ex) {
             ;
         }
         try {
             MathUtils.factorialLog(-1);
-            fail ("expecting IllegalArgumentException");
+            fail("expecting IllegalArgumentException");
         } catch (IllegalArgumentException ex) {
             ;
         }
         try {
             MathUtils.factorial(21);
-            fail ("expecting ArithmeticException");
+            fail("expecting ArithmeticException");
         } catch (ArithmeticException ex) {
             ;
         }
-        assertTrue("expecting infinite factorial value",
-            Double.isInfinite(MathUtils.factorialDouble(171)));
+        assertTrue("expecting infinite factorial value", Double.isInfinite(MathUtils.factorialDouble(171)));
     }
 
+    public void testGcd() {
+        int a = 30;
+        int b = 50;
+        int c = 77;
 
-    /**
-     * Exact recursive implementation to test against
-     */
-    private long binomialCoefficient(int n, int k) {
-        if ((n == k) || (k == 0)) {
-            return 1;
-        }
-        if ((k == 1) || (k == n - 1)) {
-            return n;
-        }
-        return binomialCoefficient(n - 1, k - 1) +
-            binomialCoefficient(n - 1, k);
-    }
-
-    /**
-     * Finds the largest values of n for which binomialCoefficient and
-     * binomialCoefficientDouble will return values that fit in a long, double,
-     * resp.  Remove comments around test below to get this in test-report
-     *
-        public void testLimits() {
-            findBinomialLimits();
-        }
-     */
+        assertEquals(0, MathUtils.gcd(0, 0));
 
-    private void findBinomialLimits() {
-        /**
-         * will kick out 66 as the limit for long
-         */
-        boolean foundLimit = false;
-        int test = 10;
-        while (!foundLimit) {
-            try {
-                MathUtils.binomialCoefficient(test, test / 2);
-            } catch (ArithmeticException ex) {
-                foundLimit = true;
-                System.out.println
-                    ("largest n for binomialCoefficient = " + (test - 1) );
-            }
-            test++;
-        }
+        assertEquals(b, MathUtils.gcd(0, b));
+        assertEquals(a, MathUtils.gcd(a, 0));
+        assertEquals(b, MathUtils.gcd(0, -b));
+        assertEquals(a, MathUtils.gcd(-a, 0));
+
+        assertEquals(10, MathUtils.gcd(a, b));
+        assertEquals(10, MathUtils.gcd(-a, b));
+        assertEquals(10, MathUtils.gcd(a, -b));
+        assertEquals(10, MathUtils.gcd(-a, -b));
 
-       /**
-        * will kick out 1029 as the limit for double
-        */
-        foundLimit = false;
-        test = 10;
-        while (!foundLimit) {
-            double x = MathUtils.binomialCoefficientDouble(test, test / 2);
-            if (Double.isInfinite(x)) {
-                foundLimit = true;
-                System.out.println
-                    ("largest n for binomialCoefficientD = " + (test - 1) );
-            }
-            test++;
-        }
+        assertEquals(1, MathUtils.gcd(a, c));
+        assertEquals(1, MathUtils.gcd(-a, c));
+        assertEquals(1, MathUtils.gcd(a, -c));
+        assertEquals(1, MathUtils.gcd(-a, -c));
     }
 
-    /**
-     * Finds the largest values of n for which factiorial and
-     * factorialDouble will return values that fit in a long, double,
-     * resp.  Remove comments around test below to get this in test-report
-
-        public void testFactiorialLimits() {
-            findFactorialLimits();
-        }
-     */
-
-    private void findFactorialLimits() {
-        /**
-         * will kick out 20 as the limit for long
-         */
-        boolean foundLimit = false;
-        int test = 10;
-        while (!foundLimit) {
-            try {
-                MathUtils.factorial(test);
-            } catch (ArithmeticException ex) {
-                foundLimit = true;
-                System.out.println
-                    ("largest n for factorial = " + (test - 1) );
-            }
-            test++;
-        }
-
-       /**
-        * will kick out 170 as the limit for double
-        */
-        foundLimit = false;
-        test = 10;
-        while (!foundLimit) {
-            double x = MathUtils.factorialDouble(test);
-            if (Double.isInfinite(x)) {
-                foundLimit = true;
-                System.out.println
-                    ("largest n for factorialDouble = " + (test - 1) );
+    public void testHash() {
+        double[] testArray = {
+            Double.NaN,
+            Double.POSITIVE_INFINITY,
+            Double.NEGATIVE_INFINITY,
+            1d,
+            0d,
+            1E-14,
+            (1 + 1E-14),
+            Double.MIN_VALUE,
+            Double.MAX_VALUE };
+        for (int i = 0; i < testArray.length; i++) {
+            for (int j = 0; j < testArray.length; j++) {
+                if (i == j) {
+                    assertEquals(MathUtils.hash(testArray[i]), MathUtils.hash(testArray[j]));
+                    assertEquals(MathUtils.hash(testArray[j]), MathUtils.hash(testArray[i]));
+                } else {
+                    assertTrue(MathUtils.hash(testArray[i]) != MathUtils.hash(testArray[j]));
+                    assertTrue(MathUtils.hash(testArray[j]) != MathUtils.hash(testArray[i]));
+                }
             }
-            test++;
-        }
-    }
-
-
-    /**
-     * Exact direct multiplication implementation to test against
-     */
-    private long factorial(int n) {
-        long result = 1;
-        for (int i = 2; i <= n; i++) {
-            result *= i;
         }
-        return result;
     }
 
-    public void testSignDouble() {
-        double delta = 0.0 ;
-        assertEquals( 1.0, MathUtils.indicator( 2.0 ), delta ) ;
-        assertEquals( -1.0, MathUtils.indicator( -2.0 ), delta ) ;
+    public void testIndicatorByte() {
+        assertEquals((byte)1, MathUtils.indicator((byte)2));
+        assertEquals((byte)1, MathUtils.indicator((byte)0));
+        assertEquals((byte)(-1), MathUtils.indicator((byte)(-2)));
     }
 
-    public void testSignFloat() {
-        float delta = 0.0F ;
-        assertEquals( 1.0F, MathUtils.indicator( 2.0F ), delta ) ;
-        assertEquals( -1.0F, MathUtils.indicator( -2.0F ), delta ) ;
+    public void testIndicatorDouble() {
+        double delta = 0.0;
+        assertEquals(1.0, MathUtils.indicator(2.0), delta);
+        assertEquals(1.0, MathUtils.indicator(0.0), delta);
+        assertEquals(-1.0, MathUtils.indicator(-2.0), delta);
     }
 
-    public void testSignByte() {
-        assertEquals( (byte)1, MathUtils.indicator( (byte)2 ) ) ;
-        assertEquals( (byte)(-1), MathUtils.indicator( (byte)(-2) ) ) ;
+    public void testIndicatorFloat() {
+        float delta = 0.0F;
+        assertEquals(1.0F, MathUtils.indicator(2.0F), delta);
+        assertEquals(1.0F, MathUtils.indicator(0.0F), delta);
+        assertEquals(-1.0F, MathUtils.indicator(-2.0F), delta);
     }
 
-    public void testSignShort() {
-        assertEquals( (short)1, MathUtils.indicator( (short)2 ) ) ;
-        assertEquals( (short)(-1), MathUtils.indicator( (short)(-2) ) ) ;
+    public void testIndicatorInt() {
+        assertEquals((int)1, MathUtils.indicator((int)(2)));
+        assertEquals((int)1, MathUtils.indicator((int)(0)));
+        assertEquals((int)(-1), MathUtils.indicator((int)(-2)));
     }
 
-    public void testSignInt() {
-        assertEquals( (int)1, MathUtils.indicator( (int)(2) ) ) ;
-        assertEquals( (int)(-1), MathUtils.indicator( (int)(-2) ) ) ;
+    public void testIndicatorLong() {
+        assertEquals(1L, MathUtils.indicator(2L));
+        assertEquals(1L, MathUtils.indicator(0L));
+        assertEquals(-1L, MathUtils.indicator(-2L));
     }
 
-    public void testSignLong() {
-        assertEquals( 1L, MathUtils.indicator( 2L ) ) ;
-        assertEquals( -1L, MathUtils.indicator( -2L ) ) ;
-    }
-   
-    public void testIndicatorDouble() {
-        double delta = 0.0 ;
-        assertEquals( 1.0, MathUtils.indicator( 2.0 ), delta ) ;
-        assertEquals( 1.0, MathUtils.indicator( 0.0 ), delta ) ;
-        assertEquals( -1.0, MathUtils.indicator( -2.0 ), delta ) ;
-    }
-    
-    public void testIndicatorFloat() {
-        float delta = 0.0F ;
-        assertEquals( 1.0F, MathUtils.indicator( 2.0F ), delta ) ;
-        assertEquals( 1.0F, MathUtils.indicator( 0.0F ), delta ) ;
-        assertEquals( -1.0F, MathUtils.indicator( -2.0F ), delta ) ;
-    }
-    
-    public void testIndicatorByte() {
-        assertEquals( (byte)1, MathUtils.indicator( (byte)2 ) ) ;
-        assertEquals( (byte)1, MathUtils.indicator( (byte)0 ) ) ;
-        assertEquals( (byte)(-1), MathUtils.indicator( (byte)(-2) ) ) ;
-    }
-    
     public void testIndicatorShort() {
-        assertEquals( (short)1, MathUtils.indicator( (short)2 ) ) ;
-        assertEquals( (short)1, MathUtils.indicator( (short)0 ) ) ;
-        assertEquals( (short)(-1), MathUtils.indicator( (short)(-2) ) ) ;
-    }
-    
-    public void testIndicatorInt() {
-        assertEquals( (int)1, MathUtils.indicator( (int)(2) ) ) ;
-        assertEquals( (int)1, MathUtils.indicator( (int)(0) ) ) ;
-        assertEquals( (int)(-1), MathUtils.indicator( (int)(-2) ) ) ;
-    }
-    
-    public void testIndicatorLong() {
-        assertEquals( 1L, MathUtils.indicator( 2L ) ) ;
-        assertEquals( 1L, MathUtils.indicator( 0L ) ) ;
-        assertEquals( -1L, MathUtils.indicator( -2L ) ) ;
-    }
-    
-    public void testCosh() {
-        double x = 3.0;
-        double expected = 10.06766;
-        assertEquals(expected, MathUtils.cosh(x), 1.0e-5);
-    }   
-    
-    public void testSinh() {
-        double x = 3.0;
-        double expected = 10.01787;
-        assertEquals(expected, MathUtils.sinh(x), 1.0e-5);
-    }   
-    
-    public void testCoshNaN() {
-        assertTrue(Double.isNaN(MathUtils.cosh(Double.NaN)));
-    }   
-    
-    public void testSinhNaN() {
-        assertTrue(Double.isNaN(MathUtils.sinh(Double.NaN)));
-    } 
-    
-    public void testEquals() {
-        double[] testArray = {Double.NaN, Double.POSITIVE_INFINITY, 
-                Double.NEGATIVE_INFINITY, 1d, 0d};
-        for (int i = 0; i < testArray.length; i++) {
-            for (int j = 0; j < testArray.length; j ++) {
-                if (i == j) {
-                    assertTrue(MathUtils.equals(testArray[i], testArray[j]));
-                    assertTrue(MathUtils.equals(testArray[j], testArray[i]));
-                } else {
-                    assertTrue(!MathUtils.equals(testArray[i], testArray[j]));
-                    assertTrue(!MathUtils.equals(testArray[j], testArray[i]));
-                }
-            }
-        } 
-    }
-    
-    public void testHash() {
-        double[] testArray = {Double.NaN, Double.POSITIVE_INFINITY, 
-                Double.NEGATIVE_INFINITY, 1d, 0d, 1E-14, (1 + 1E-14), 
-                Double.MIN_VALUE, Double.MAX_VALUE};
-        for (int i = 0; i < testArray.length; i++) {
-            for (int j = 0; j < testArray.length; j ++) {
-                if (i == j) {
-                    assertEquals(MathUtils.hash(testArray[i]), MathUtils.hash(testArray[j]));
-                    assertEquals(MathUtils.hash(testArray[j]), MathUtils.hash(testArray[i]));
-                } else {
-                    assertTrue(MathUtils.hash(testArray[i]) != MathUtils.hash(testArray[j]));
-                    assertTrue(MathUtils.hash(testArray[j]) != MathUtils.hash(testArray[i]));
-                }
-            }
-        } 
+        assertEquals((short)1, MathUtils.indicator((short)2));
+        assertEquals((short)1, MathUtils.indicator((short)0));
+        assertEquals((short)(-1), MathUtils.indicator((short)(-2)));
     }
-    
-    public void testLog() {
-    	assertEquals(2.0, MathUtils.log(2,4), 0);
-    	assertEquals(3.0, MathUtils.log(2,8), 0);
-        assertTrue(Double.isNaN(MathUtils.log(-1, 1)));
-        assertTrue(Double.isNaN(MathUtils.log(1, -1)));
-        assertTrue(Double.isNaN(MathUtils.log(0, 0)));
-        assertEquals(0, MathUtils.log(0, 10), 0);
-        assertEquals(Double.NEGATIVE_INFINITY, MathUtils.log(10, 0), 0);
-    }
-    
-    public void testGcd() {
-        int a = 30;
-        int b = 50;
-        int c = 77;
 
-        assertEquals(0, MathUtils.gcd(0, 0));
-        
-        assertEquals(b, MathUtils.gcd( 0,  b));
-        assertEquals(a, MathUtils.gcd( a,  0));
-        assertEquals(b, MathUtils.gcd( 0, -b));
-        assertEquals(a, MathUtils.gcd(-a,  0));
-        
-        assertEquals(10, MathUtils.gcd( a,  b));
-        assertEquals(10, MathUtils.gcd(-a,  b));
-        assertEquals(10, MathUtils.gcd( a, -b));
-        assertEquals(10, MathUtils.gcd(-a, -b));
-        
-        assertEquals(1, MathUtils.gcd( a,  c));
-        assertEquals(1, MathUtils.gcd(-a,  c));
-        assertEquals(1, MathUtils.gcd( a, -c));
-        assertEquals(1, MathUtils.gcd(-a, -c));
-    }
-    
     public void testLcm() {
         int a = 30;
         int b = 50;
         int c = 77;
-        
+
         assertEquals(0, MathUtils.lcm(0, b));
         assertEquals(0, MathUtils.lcm(a, 0));
         assertEquals(b, MathUtils.lcm(1, b));
@@ -489,7 +346,7 @@
         assertEquals(150, MathUtils.lcm(-a, b));
         assertEquals(150, MathUtils.lcm(a, -b));
         assertEquals(2310, MathUtils.lcm(a, c));
-        
+
         try {
             MathUtils.lcm(Integer.MAX_VALUE, Integer.MAX_VALUE - 1);
             fail("Expecting ArithmeticException");
@@ -497,114 +354,61 @@
             // expected
         }
     }
-    public void testRoundFloat() {
-        float x = 1.234567890f;
-        assertEquals(1.23f, MathUtils.round(x, 2), 0.0);
-        assertEquals(1.235f, MathUtils.round(x, 3), 0.0);
-        assertEquals(1.2346f, MathUtils.round(x, 4), 0.0);
-        
-        // BZ 35904
-        assertEquals(30.1f, MathUtils.round(30.095f, 2), 0.0f);
-        assertEquals(30.1f, MathUtils.round(30.095f, 1), 0.0f);
-        assertEquals(50.09f,  MathUtils.round(50.085f, 2), 0.0f);
-        assertEquals(50.19f,  MathUtils.round(50.185f, 2), 0.0f);
-        assertEquals(50.01f,  MathUtils.round(50.005f, 2), 0.0f);
-        assertEquals(30.01f,  MathUtils.round(30.005f, 2), 0.0f);
-        assertEquals(30.65f,  MathUtils.round(30.645f, 2), 0.0f);
-        
-        assertEquals(1.24f, MathUtils.round(x, 2, BigDecimal.ROUND_CEILING), 0.0);
-        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_CEILING), 0.0);
-        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_CEILING), 0.0);
-        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_CEILING), 0.0);
-        assertEquals(-1.234f, MathUtils.round(-x, 3, BigDecimal.ROUND_CEILING), 0.0);
-        assertEquals(-1.2345f, MathUtils.round(-x, 4, BigDecimal.ROUND_CEILING), 0.0);
 
-        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_DOWN), 0.0);
-        assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_DOWN), 0.0);
-        assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_DOWN), 0.0);
-        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_DOWN), 0.0);
-        assertEquals(-1.234f, MathUtils.round(-x, 3, BigDecimal.ROUND_DOWN), 0.0);
-        assertEquals(-1.2345f, MathUtils.round(-x, 4, BigDecimal.ROUND_DOWN), 0.0);
-        
-        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_FLOOR), 0.0);
-        assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_FLOOR), 0.0);
-        assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_FLOOR), 0.0);
-        assertEquals(-1.24f, MathUtils.round(-x, 2, BigDecimal.ROUND_FLOOR), 0.0);
-        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_FLOOR), 0.0);
-        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_FLOOR), 0.0);
-        
-        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(1.234f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        assertEquals(-1.234f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        
-        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(1.234f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(-1.234f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(1.236f, MathUtils.round(1.2355f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        assertEquals(-1.236f, MathUtils.round(-1.2355f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        
-        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(1.235f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_UP), 0.0);
-        assertEquals(-1.235f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_UP), 0.0);
-        
-        assertEquals(-1.23f, MathUtils.round(-1.23f, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
-        assertEquals(1.23f, MathUtils.round(1.23f, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
-        
+    public void testLog() {
+        assertEquals(2.0, MathUtils.log(2, 4), 0);
+        assertEquals(3.0, MathUtils.log(2, 8), 0);
+        assertTrue(Double.isNaN(MathUtils.log(-1, 1)));
+        assertTrue(Double.isNaN(MathUtils.log(1, -1)));
+        assertTrue(Double.isNaN(MathUtils.log(0, 0)));
+        assertEquals(0, MathUtils.log(0, 10), 0);
+        assertEquals(Double.NEGATIVE_INFINITY, MathUtils.log(10, 0), 0);
+    }
+
+    public void testMulAndCheck() {
+        int big = Integer.MAX_VALUE;
+        int bigNeg = Integer.MIN_VALUE;
+        assertEquals(big, MathUtils.mulAndCheck(big, 1));
         try {
-            MathUtils.round(1.234f, 2, BigDecimal.ROUND_UNNECESSARY);
-            fail();
+            MathUtils.mulAndCheck(big, 2);
+            fail("Expecting ArithmeticException");
         } catch (ArithmeticException ex) {
-            // success
         }
-        
-        assertEquals(1.24f, MathUtils.round(x, 2, BigDecimal.ROUND_UP), 0.0);
-        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_UP), 0.0);
-        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_UP), 0.0);
-        assertEquals(-1.24f, MathUtils.round(-x, 2, BigDecimal.ROUND_UP), 0.0);
-        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_UP), 0.0);
-        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_UP), 0.0);
-        
         try {
-            MathUtils.round(1.234f, 2, 1923);
-            fail();
-        } catch (IllegalArgumentException ex) {
-            // success
+            MathUtils.mulAndCheck(bigNeg, 2);
+            fail("Expecting ArithmeticException");
+        } catch (ArithmeticException ex) {
         }
-        
-        // 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 testNextAfterSpecialCases() {
-        assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.NEGATIVE_INFINITY, 0)));
-        assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.POSITIVE_INFINITY, 0)));
-        assertTrue(Double.isNaN(MathUtils.nextAfter(Double.NaN, 0)));
-        assertTrue(Double.isInfinite(MathUtils.nextAfter( Double.MAX_VALUE, Double.POSITIVE_INFINITY)));
-        assertTrue(Double.isInfinite(MathUtils.nextAfter(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY)));
-        assertEquals( Double.MIN_VALUE, MathUtils.nextAfter(0,  1), 0);
-        assertEquals(-Double.MIN_VALUE, MathUtils.nextAfter(0, -1), 0);
-        assertEquals(0, MathUtils.nextAfter( Double.MIN_VALUE, -1), 0);
-        assertEquals(0, MathUtils.nextAfter(-Double.MIN_VALUE,  1), 0);
+
+    public void testMulAndCheckLong() {
+        long max = Long.MAX_VALUE;
+        long min = Long.MIN_VALUE;
+        assertEquals(max, MathUtils.mulAndCheck(max, 1L));
+        assertEquals(min, MathUtils.mulAndCheck(min, 1L));
+        assertEquals(0L, MathUtils.mulAndCheck(max, 0L));
+        assertEquals(0L, MathUtils.mulAndCheck(min, 0L));
+        assertEquals(max, MathUtils.mulAndCheck(1L, max));
+        assertEquals(min, MathUtils.mulAndCheck(1L, min));
+        assertEquals(0L, MathUtils.mulAndCheck(0L, max));
+        assertEquals(0L, MathUtils.mulAndCheck(0L, min));
+        testMulAndCheckLongFailure(max, 2L);
+        testMulAndCheckLongFailure(2L, max);
+        testMulAndCheckLongFailure(min, 2L);
+        testMulAndCheckLongFailure(2L, min);
+        testMulAndCheckLongFailure(min, -1L);
+        testMulAndCheckLongFailure(-1L, min);
+    }
+
+    private void testMulAndCheckLongFailure(long a, long b) {
+        try {
+            MathUtils.mulAndCheck(a, b);
+            fail("Expecting ArithmeticException");
+        } catch (ArithmeticException ex) {
+            // success
+        }
     }
-    
+
     public void testNextAfter() {
         // 0x402fffffffffffff 0x404123456789abcd -> 4030000000000000
         assertEquals(16.0, MathUtils.nextAfter(15.999999999999998, 34.27555555555555), 0.0);
@@ -668,31 +472,42 @@
 
     }
 
+    public void testNextAfterSpecialCases() {
+        assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.NEGATIVE_INFINITY, 0)));
+        assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.POSITIVE_INFINITY, 0)));
+        assertTrue(Double.isNaN(MathUtils.nextAfter(Double.NaN, 0)));
+        assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.MAX_VALUE, Double.POSITIVE_INFINITY)));
+        assertTrue(Double.isInfinite(MathUtils.nextAfter(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY)));
+        assertEquals(Double.MIN_VALUE, MathUtils.nextAfter(0, 1), 0);
+        assertEquals(-Double.MIN_VALUE, MathUtils.nextAfter(0, -1), 0);
+        assertEquals(0, MathUtils.nextAfter(Double.MIN_VALUE, -1), 0);
+        assertEquals(0, MathUtils.nextAfter(-Double.MIN_VALUE, 1), 0);
+    }
+
     public void testRoundDouble() {
         double x = 1.234567890;
         assertEquals(1.23, MathUtils.round(x, 2), 0.0);
         assertEquals(1.235, MathUtils.round(x, 3), 0.0);
         assertEquals(1.2346, MathUtils.round(x, 4), 0.0);
-        
+
         // JIRA MATH-151
-        assertEquals(39.25,MathUtils.round(39.245, 2), 0.0);
-        assertEquals(39.24,MathUtils.round(39.245, 2, 
-                BigDecimal.ROUND_DOWN), 0.0);
+        assertEquals(39.25, MathUtils.round(39.245, 2), 0.0);
+        assertEquals(39.24, MathUtils.round(39.245, 2, BigDecimal.ROUND_DOWN), 0.0);
         double xx = 39.0;
-        xx = xx + 245d/1000d;
-        assertEquals(39.25,MathUtils.round(xx, 2), 0.0);
-        
+        xx = xx + 245d / 1000d;
+        assertEquals(39.25, MathUtils.round(xx, 2), 0.0);
+
         // BZ 35904
         assertEquals(30.1d, MathUtils.round(30.095d, 2), 0.0d);
         assertEquals(30.1d, MathUtils.round(30.095d, 1), 0.0d);
         assertEquals(33.1d, MathUtils.round(33.095d, 1), 0.0d);
         assertEquals(33.1d, MathUtils.round(33.095d, 2), 0.0d);
-        assertEquals(50.09d,  MathUtils.round(50.085d, 2), 0.0d);
-        assertEquals(50.19d,  MathUtils.round(50.185d, 2), 0.0d);
-        assertEquals(50.01d,  MathUtils.round(50.005d, 2), 0.0d);
-        assertEquals(30.01d,  MathUtils.round(30.005d, 2), 0.0d);
-        assertEquals(30.65d,  MathUtils.round(30.645d, 2), 0.0d);
-        
+        assertEquals(50.09d, MathUtils.round(50.085d, 2), 0.0d);
+        assertEquals(50.19d, MathUtils.round(50.185d, 2), 0.0d);
+        assertEquals(50.01d, MathUtils.round(50.005d, 2), 0.0d);
+        assertEquals(30.01d, MathUtils.round(30.005d, 2), 0.0d);
+        assertEquals(30.65d, MathUtils.round(30.645d, 2), 0.0d);
+
         assertEquals(1.24, MathUtils.round(x, 2, BigDecimal.ROUND_CEILING), 0.0);
         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_CEILING), 0.0);
         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_CEILING), 0.0);
@@ -706,14 +521,14 @@
         assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_DOWN), 0.0);
         assertEquals(-1.234, MathUtils.round(-x, 3, BigDecimal.ROUND_DOWN), 0.0);
         assertEquals(-1.2345, MathUtils.round(-x, 4, BigDecimal.ROUND_DOWN), 0.0);
-        
+
         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_FLOOR), 0.0);
         assertEquals(1.234, MathUtils.round(x, 3, BigDecimal.ROUND_FLOOR), 0.0);
         assertEquals(1.2345, MathUtils.round(x, 4, BigDecimal.ROUND_FLOOR), 0.0);
         assertEquals(-1.24, MathUtils.round(-x, 2, BigDecimal.ROUND_FLOOR), 0.0);
         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_FLOOR), 0.0);
         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_FLOOR), 0.0);
-        
+
         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
@@ -722,7 +537,7 @@
         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
         assertEquals(1.234, MathUtils.round(1.2345, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
         assertEquals(-1.234, MathUtils.round(-1.2345, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
-        
+
         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
@@ -733,7 +548,7 @@
         assertEquals(-1.234, MathUtils.round(-1.2345, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
         assertEquals(1.236, MathUtils.round(1.2355, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
         assertEquals(-1.236, MathUtils.round(-1.2355, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
-        
+
         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
@@ -742,24 +557,24 @@
         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
         assertEquals(1.235, MathUtils.round(1.2345, 3, BigDecimal.ROUND_HALF_UP), 0.0);
         assertEquals(-1.235, MathUtils.round(-1.2345, 3, BigDecimal.ROUND_HALF_UP), 0.0);
-        
+
         assertEquals(-1.23, MathUtils.round(-1.23, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
         assertEquals(1.23, MathUtils.round(1.23, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
-        
+
         try {
             MathUtils.round(1.234, 2, BigDecimal.ROUND_UNNECESSARY);
             fail();
         } catch (ArithmeticException ex) {
             // success
         }
-        
+
         assertEquals(1.24, MathUtils.round(x, 2, BigDecimal.ROUND_UP), 0.0);
         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_UP), 0.0);
         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_UP), 0.0);
         assertEquals(-1.24, MathUtils.round(-x, 2, BigDecimal.ROUND_UP), 0.0);
         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_UP), 0.0);
         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_UP), 0.0);
-        
+
         try {
             MathUtils.round(1.234, 2, 1923);
             fail();
@@ -769,11 +584,196 @@
 
         // MATH-151
         assertEquals(39.25, MathUtils.round(39.245, 2, BigDecimal.ROUND_HALF_UP), 0.0);
-     
+
         // 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);
+    }
+
+    public void testRoundFloat() {
+        float x = 1.234567890f;
+        assertEquals(1.23f, MathUtils.round(x, 2), 0.0);
+        assertEquals(1.235f, MathUtils.round(x, 3), 0.0);
+        assertEquals(1.2346f, MathUtils.round(x, 4), 0.0);
+
+        // BZ 35904
+        assertEquals(30.1f, MathUtils.round(30.095f, 2), 0.0f);
+        assertEquals(30.1f, MathUtils.round(30.095f, 1), 0.0f);
+        assertEquals(50.09f, MathUtils.round(50.085f, 2), 0.0f);
+        assertEquals(50.19f, MathUtils.round(50.185f, 2), 0.0f);
+        assertEquals(50.01f, MathUtils.round(50.005f, 2), 0.0f);
+        assertEquals(30.01f, MathUtils.round(30.005f, 2), 0.0f);
+        assertEquals(30.65f, MathUtils.round(30.645f, 2), 0.0f);
+
+        assertEquals(1.24f, MathUtils.round(x, 2, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(-1.234f, MathUtils.round(-x, 3, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(-1.2345f, MathUtils.round(-x, 4, BigDecimal.ROUND_CEILING), 0.0);
+
+        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_DOWN), 0.0);
+        assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_DOWN), 0.0);
+        assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_DOWN), 0.0);
+        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_DOWN), 0.0);
+        assertEquals(-1.234f, MathUtils.round(-x, 3, BigDecimal.ROUND_DOWN), 0.0);
+        assertEquals(-1.2345f, MathUtils.round(-x, 4, BigDecimal.ROUND_DOWN), 0.0);
+
+        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_FLOOR), 0.0);
+        assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_FLOOR), 0.0);
+        assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_FLOOR), 0.0);
+        assertEquals(-1.24f, MathUtils.round(-x, 2, BigDecimal.ROUND_FLOOR), 0.0);
+        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_FLOOR), 0.0);
+        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_FLOOR), 0.0);
+
+        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(1.234f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
+        assertEquals(-1.234f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
+
+        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(1.234f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(-1.234f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(1.236f, MathUtils.round(1.2355f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        assertEquals(-1.236f, MathUtils.round(-1.2355f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+
+        assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(1.235f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_UP), 0.0);
+        assertEquals(-1.235f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_UP), 0.0);
+
+        assertEquals(-1.23f, MathUtils.round(-1.23f, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
+        assertEquals(1.23f, MathUtils.round(1.23f, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
+
+        try {
+            MathUtils.round(1.234f, 2, BigDecimal.ROUND_UNNECESSARY);
+            fail();
+        } catch (ArithmeticException ex) {
+            // success
+        }
+
+        assertEquals(1.24f, MathUtils.round(x, 2, BigDecimal.ROUND_UP), 0.0);
+        assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_UP), 0.0);
+        assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_UP), 0.0);
+        assertEquals(-1.24f, MathUtils.round(-x, 2, BigDecimal.ROUND_UP), 0.0);
+        assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_UP), 0.0);
+        assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_UP), 0.0);
+
+        try {
+            MathUtils.round(1.234f, 2, 1923);
+            fail();
+        } 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 testSignByte() {
+        assertEquals((byte)1, MathUtils.indicator((byte)2));
+        assertEquals((byte)(-1), MathUtils.indicator((byte)(-2)));
+    }
+
+    public void testSignDouble() {
+        double delta = 0.0;
+        assertEquals(1.0, MathUtils.indicator(2.0), delta);
+        assertEquals(-1.0, MathUtils.indicator(-2.0), delta);
+    }
+
+    public void testSignFloat() {
+        float delta = 0.0F;
+        assertEquals(1.0F, MathUtils.indicator(2.0F), delta);
+        assertEquals(-1.0F, MathUtils.indicator(-2.0F), delta);
+    }
+
+    public void testSignInt() {
+        assertEquals((int)1, MathUtils.indicator((int)(2)));
+        assertEquals((int)(-1), MathUtils.indicator((int)(-2)));
+    }
+
+    public void testSignLong() {
+        assertEquals(1L, MathUtils.indicator(2L));
+        assertEquals(-1L, MathUtils.indicator(-2L));
+    }
+
+    public void testSignShort() {
+        assertEquals((short)1, MathUtils.indicator((short)2));
+        assertEquals((short)(-1), MathUtils.indicator((short)(-2)));
+    }
+
+    public void testSinh() {
+        double x = 3.0;
+        double expected = 10.01787;
+        assertEquals(expected, MathUtils.sinh(x), 1.0e-5);
+    }
+
+    public void testSinhNaN() {
+        assertTrue(Double.isNaN(MathUtils.sinh(Double.NaN)));
+    }
+
+    public void testSubAndCheck() {
+        int big = Integer.MAX_VALUE;
+        int bigNeg = Integer.MIN_VALUE;
+        assertEquals(big, MathUtils.subAndCheck(big, 0));
+        try {
+            MathUtils.subAndCheck(big, -1);
+            fail("Expecting ArithmeticException");
+        } catch (ArithmeticException ex) {
+        }
+        try {
+            MathUtils.subAndCheck(bigNeg, 1);
+            fail("Expecting ArithmeticException");
+        } catch (ArithmeticException ex) {
+        }
+    }
+
+    public void testSubAndCheckErrorMessage() {
+        int big = Integer.MAX_VALUE;
+        try {
+            MathUtils.subAndCheck(big, -1);
+            fail("Expecting ArithmeticException");
+        } catch (ArithmeticException ex) {
+            assertEquals("overflow: subtract", ex.getMessage());
+        }
+    }
+
+    public void testSubAndCheckLong() {
+        long max = Long.MAX_VALUE;
+        long min = Long.MIN_VALUE;
+        assertEquals(max, MathUtils.subAndCheck(max, 0));
+        assertEquals(min, MathUtils.subAndCheck(min, 0));
+        assertEquals(-max, MathUtils.subAndCheck(0, max));
+        testSubAndCheckLongFailure(0L, min);
+        testSubAndCheckLongFailure(max, -1L);
+        testSubAndCheckLongFailure(min, 1L);
+    }
+
+    private void testSubAndCheckLongFailure(long a, long b) {
+        try {
+            MathUtils.subAndCheck(a, b);
+            fail("Expecting ArithmeticException");
+        } catch (ArithmeticException ex) {
+            // success
+        }
+
     }
 }

Modified: commons/proper/math/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/xdocs/changes.xml?rev=590577&r1=590576&r2=590577&view=diff
==============================================================================
--- commons/proper/math/trunk/xdocs/changes.xml (original)
+++ commons/proper/math/trunk/xdocs/changes.xml Wed Oct 31 00:23:01 2007
@@ -98,6 +98,10 @@
       <action dev="brentworden" type="update" issue="MATH-170" due-to="David J. M. Karlsen">
         Added SynchronizedDescriptiveStatistics class.
       </action>
+      <action dev="brentworden" type="update" issue="MATH-154" due-to="Remi Arntzen">
+        Added addAndCheck, mulAndCheck, and subAndCheck MathUtils methods for
+        long integer arguments.
+      </action>
     </release>
     <release version="1.1" date="2005-12-17"  
  description="This is a maintenance release containing bug fixes and enhancements.