You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by br...@apache.org on 2005/08/09 15:10:30 UTC

svn commit: r231029 - in /jakarta/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: Tue Aug  9 06:10:26 2005
New Revision: 231029

URL: http://svn.apache.org/viewcvs?rev=231029&view=rev
Log:
PR: 35904
Changed rounding methods to not rely on BigDecimal conversions which was causing numerical error.

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

Modified: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java?rev=231029&r1=231028&r2=231029&view=diff
==============================================================================
--- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java (original)
+++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java Tue Aug  9 06:10:26 2005
@@ -1,17 +1,12 @@
 /*
- * 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-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.
  */
 
 package org.apache.commons.math.util;
@@ -20,283 +15,74 @@
 
 /**
  * Some useful additions to the built-in functions in {@link Math}.
- *
- * @version $Revision$ $Date$
+ * 
+ * @version $Revision$ $Date: 2005-07-30 02:25:26 -0500 (Sat, 30 Jul
+ *          2005) $
  */
 public final class MathUtils {
-    
-    /** 0.0 cast as a byte. */
-    private static final byte ZB = (byte) 0;
-    
+
     /** -1.0 cast as a byte. */
-    private static final byte NB = (byte) -1;
-    
-    /** 1.0 cast as a byte. */
-    private static final byte PB = (byte) 1;
-    
-    /** 0.0 cast as a short. */
-    private static final short ZS = (short) 0;
-    
+    private static final byte  NB = (byte)-1;
+
     /** -1.0 cast as a short. */
-    private static final short NS = (short) -1;
-    
+    private static final short NS = (short)-1;
+
+    /** 1.0 cast as a byte. */
+    private static final byte  PB = (byte)1;
+
     /** 1.0 cast as a short. */
-    private static final short PS = (short) 1;
-    
+    private static final short PS = (short)1;
+
+    /** 0.0 cast as a byte. */
+    private static final byte  ZB = (byte)0;
+
+    /** 0.0 cast as a short. */
+    private static final short ZS = (short)0;
+
     /**
      * Private Constructor
      */
     private MathUtils() {
-    }
-    
-    /**
-     * Round the given value to the specified number of decimal places.  The
-     * value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
-     * @param x the value to round.
-     * @param scale the number of digits to the right of the decimal point.
-     * @return the rounded value.
-     * @since 1.1
-     */
-    public static double round(double x, int scale) {
-        return round(x, scale, BigDecimal.ROUND_HALF_UP);
-    }
-
-    /**
-     * Round the given value to the specified number of decimal places.  The
-     * value is rounded using the given method which is any method defined in
-     * {@link BigDecimal}.
-     * @param x the value to round.
-     * @param scale the number of digits to the right of the decimal point.
-     * @param roundingMethod the rounding method as defined in
-     *        {@link BigDecimal}. 
-     * @return the rounded value.
-     * @since 1.1
-     */
-    public static double round(
-        double x, int scale, int roundingMethod)
-    {
-        return (new BigDecimal(new Double(x).toString()).setScale(scale, roundingMethod))
-            .doubleValue();
-    }
-    
-    /**
-     * Round the given value to the specified number of decimal places.  The
-     * value is rounding using the {@link BigDecimal#ROUND_HALF_UP} method.
-     * @param x the value to round.
-     * @param scale the number of digits to the right of the decimal point.
-     * @return the rounded value.
-     * @since 1.1
-     */
-    public static float round(float x, int scale) {
-        return round(x, scale, BigDecimal.ROUND_HALF_UP);
+        super();
     }
 
     /**
-     * Round the given value to the specified number of decimal places.  The
-     * value is rounded using the given method which is any method defined in
-     * {@link BigDecimal}.
-     * @param x the value to round.
-     * @param scale the number of digits to the right of the decimal point.
-     * @param roundingMethod the rounding method as defined in
-     *        {@link BigDecimal}. 
-     * @return the rounded value.
+     * Add two integers, checking for overflow.
+     * 
+     * @param x an addend
+     * @param y an addend
+     * @return the sum <code>x+y</code>
+     * @throws ArithmeticException if the result can not be represented as an
+     *         int
      * @since 1.1
      */
-    public static float round(float x, int scale, int roundingMethod) {
-        return (new BigDecimal(new Float(x).toString()).setScale(scale, roundingMethod)).floatValue();
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/Sign.html">
-     * sign</a> for double precision <code>x</code>.
-     *
-     * <p>
-     * For a double value <code>x</code>, this method returns <code>+1.0</code>
-     * if <code>x > 0</code>, <code>0.0</code> if <code>x = 0.0</code>,
-     * and <code>-1.0</code> if <code>x < 0</code>.  Returns <code>NaN</code> 
-     * if <code>x</code> is <code>NaN</code>.
-     *
-     * @param x the value, a double
-     * @return +1.0, 0.0, or -1.0, depending on the sign of x
-     */
-    public static double sign(final double x) {
-        if (Double.isNaN(x)) {
-            return Double.NaN;
-        }
-        return (x == 0.0) ? 0.0 : (x > 0.0) ? 1.0 : -1.0;
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/Sign.html">
-     * sign</a> for float value <code>x</code>.
-     *
-     * <p>
-     * For a float value x, this method returns +1.0F if x > 0, 0.0F if
-     * x = 0.0F, and -1.0F if x < 0.  Returns <code>NaN</code> 
-     * if <code>x</code> is <code>NaN</code>.
-     *
-     * @param x the value, a float
-     * @return +1.0F, 0.0F, or -1.0F, depending on the sign of x
-     */
-    public static float sign(final float x) {
-        if (Float.isNaN(x)) {
-            return Float.NaN;
-        }
-        return (x == 0.0F) ? 0.0F : (x > 0.0F) ? 1.0F : -1.0F;
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/Sign.html">
-     * sign</a> for byte value <code>x</code>.
-     *
-     * <p>
-     * For a byte value x, this method returns (byte)(+1) if x > 0, (byte)(0)
-     * if x = 0, and (byte)(-1) if x < 0.
-     *
-     * @param x the value, a byte
-     * @return (byte)(+1), (byte)(0), or (byte)(-1), depending on the sign of x
-     */
-    public static byte sign(final byte x) {
-        return (x == ZB) ? ZB : (x > ZB) ? PB : NB;
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/Sign.html">
-     * sign</a> for short value <code>x</code>.
-     *
-     * <p>
-     * For a short value x, this method returns (short)(+1) if x > 0, (short)(0)
-     * if x = 0, and (short)(-1) if x < 0.
-     *
-     * @param x the value, a short
-     * @return (short)(+1), (short)(0), or (short)(-1), depending on the sign
-     * of x
-     */
-    public static short sign(final short x) {
-        return (x == ZS) ? ZS : (x > ZS) ? PS : NS;
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/Sign.html">
-     * sign</a> for int value <code>x</code>.
-     *
-     * <p>
-     * For an int value x, this method returns +1 if x > 0, 0 if x = 0,
-     * and -1 if x < 0.
-     *
-     * @param x the value, an int
-     * @return +1, 0, or -1, depending on the sign of x
-     */
-    public static int sign(final int x) {
-        return (x == 0) ? 0 : (x > 0) ? 1 : -1;
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/Sign.html">
-     * sign</a> for long value <code>x</code>.
-     *
-     * <p>
-     * For a long value x, this method returns +1L if x > 0, 0L if x = 0,
-     * and -1L if x < 0.
-     *
-     * @param x the value, a long
-     * @return +1L, 0L, or -1L, depending on the sign of x
-     */
-    public static long sign(final long x) {
-        return (x == 0L) ? 0L : (x > 0L) ? 1L : -1L;
-    }
-    
-    /**
-     * For a double precision value x, this method returns +1.0 if x >= 0
-     * and -1.0 if x < 0.   Returns <code>NaN</code> 
-     * if <code>x</code> is <code>NaN</code>.
-     *
-     * @param x the value, a double
-     * @return +1.0 or -1.0, depending on the sign of x
-     */
-    public static double indicator(final double x) {
-        if (Double.isNaN(x)) {
-            return Double.NaN;
-        }
-        return (x >= 0.0) ? 1.0 : -1.0;
-    }
-    
-    /**
-     * For a float value x, this method returns +1.0F if x >= 0
-     * and -1.0F if x < 0.   Returns <code>NaN</code> 
-     * if <code>x</code> is <code>NaN</code>.
-     *
-     * @param x the value, a float
-     * @return +1.0F or -1.0F, depending on the sign of x
-     */
-    public static float indicator(final float x) {
-        if (Float.isNaN(x)) {
-            return Float.NaN;
+    public static int addAndCheck(int x, int y) {
+        long s = (long)x + (long)y;
+        if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
+            throw new ArithmeticException("overflow: add");
         }
-        return (x >= 0.0F) ? 1.0F : -1.0F;
-    }
-    
-    /**
-     * For a byte value x, this method returns (byte)(+1) if x >= 0
-     * and (byte)(-1) if x < 0.
-     *
-     * @param x the value, a byte
-     * @return (byte)(+1) or (byte)(-1), depending on the sign of x
-     */
-    public static byte indicator(final byte x) {
-        return (x >= ZB) ? PB : NB;
-    }
-    
-    /**
-     * For a short value x, this method returns (short)(+1) if x >= 0
-     * and (short)(-1) if x < 0.
-     *
-     * @param x the value, a short
-     * @return (short)(+1) or (short)(-1), depending on the sign of x
-     */
-    public static short indicator(final short x) {
-        return (x >= ZS) ? PS : NS;
-    }
-    
-    /**
-     * For an int value x, this method returns +1 if x >= 0
-     * and -1 if x < 0.
-     *
-     * @param x the value, an int
-     * @return +1 or -1, depending on the sign of x
-     */
-    public static int indicator(final int x) {
-        return (x >= 0) ? 1 : -1;
-    }
-    
-    /**
-     * For a long value x, this method returns +1L if x >= 0
-     * and -1L if x < 0.
-     *
-     * @param x the value, a long
-     * @return +1L or -1L, depending on the sign of x
-     */
-    public static long indicator(final long x) {
-        return (x >= 0L) ? 1L : -1L;
+        return (int)s;
     }
-    
+
     /**
-     * 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 <code>k</code>-element subsets that can be selected from
-     * an <code>n</code>-element set.
+     * 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
+     * <code>k</code>-element subsets that can be selected from an
+     * <code>n</code>-element set.
      * <p>
-     * <Strong>Preconditions</strong>:<ul>
+     * <Strong>Preconditions</strong>:
+     * <ul>
      * <li> <code>0 <= k <= n </code> (otherwise
-     *      <code>IllegalArgumentException</code> is thrown)</li>
-     * <li> The result is small enough to fit into a <code>long</code>.  The
-     *      largest value of <code>n</code> for which all coefficients are
-     *      <code> < Long.MAX_VALUE</code> is 66.  If the computed value
-     *      exceeds <code>Long.MAX_VALUE</code> an <code>ArithMeticException
-     *      </code> is thrown.</li>
+     * <code>IllegalArgumentException</code> is thrown)</li>
+     * <li> The result is small enough to fit into a <code>long</code>. The
+     * largest value of <code>n</code> for which all coefficients are
+     * <code> < Long.MAX_VALUE</code> is 66. If the computed value exceeds
+     * <code>Long.MAX_VALUE</code> an <code>ArithMeticException
+     *      </code> is
+     * thrown.</li>
      * </ul>
-     *
+     * 
      * @param n the size of the set
      * @param k the size of the subsets to be counted
      * @return <code>n choose k</code>
@@ -307,11 +93,11 @@
     public static long binomialCoefficient(final int n, final int k) {
         if (n < k) {
             throw new IllegalArgumentException(
-            "must have n >= k for binomial coefficient (n,k)");
+                "must have n >= k for binomial coefficient (n,k)");
         }
         if (n < 0) {
             throw new IllegalArgumentException(
-            "must have n >= 0 for binomial coefficient (n,k)");
+                "must have n >= 0 for binomial coefficient (n,k)");
         }
         if ((n == k) || (k == 0)) {
             return 1;
@@ -319,31 +105,32 @@
         if ((k == 1) || (k == n - 1)) {
             return n;
         }
-        
+
         long result = Math.round(binomialCoefficientDouble(n, k));
         if (result == Long.MAX_VALUE) {
             throw new ArithmeticException(
-            "result too large to represent in a long integer");
+                "result too large to represent in a long integer");
         }
         return result;
     }
-    
+
     /**
-     * Returns a <code>double</code> representation of the
-     * <a href="http://mathworld.wolfram.com/BinomialCoefficient.html">
-     * Binomial Coefficient</a>,  "<code>n choose k</code>",
-     * the number of <code>k</code>-element subsets that can be selected from
-     * an <code>n</code>-element set.
+     * Returns a <code>double</code> representation of the <a
+     * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
+     * Coefficient</a>, "<code>n choose k</code>", the number of
+     * <code>k</code>-element subsets that can be selected from an
+     * <code>n</code>-element set.
      * <p>
-     * <Strong>Preconditions</strong>:<ul>
+     * <Strong>Preconditions</strong>:
+     * <ul>
      * <li> <code>0 <= k <= n </code> (otherwise
-     *      <code>IllegalArgumentException</code> is thrown)</li>
-     * <li> The result is small enough to fit into a <code>double</code>.
-     *      The largest value of <code>n</code> for which all coefficients are
-     *      < Double.MAX_VALUE is 1029.  If the computed value exceeds
-     *      Double.MAX_VALUE, Double.POSITIVE_INFINITY is returned</li>
+     * <code>IllegalArgumentException</code> is thrown)</li>
+     * <li> The result is small enough to fit into a <code>double</code>. The
+     * largest value of <code>n</code> for which all coefficients are <
+     * Double.MAX_VALUE is 1029. If the computed value exceeds Double.MAX_VALUE,
+     * Double.POSITIVE_INFINITY is returned</li>
      * </ul>
-     *
+     * 
      * @param n the size of the set
      * @param k the size of the subsets to be counted
      * @return <code>n choose k</code>
@@ -352,19 +139,20 @@
     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 Coefficient</a>,  "<code>n choose k</code>",
-     * the number of <code>k</code>-element subsets that can be selected from
-     * an <code>n</code>-element set.
+     * Returns the natural <code>log</code> of the <a
+     * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
+     * Coefficient</a>, "<code>n choose k</code>", the number of
+     * <code>k</code>-element subsets that can be selected from an
+     * <code>n</code>-element set.
      * <p>
-     * <Strong>Preconditions</strong>:<ul>
+     * <Strong>Preconditions</strong>:
+     * <ul>
      * <li> <code>0 <= k <= n </code> (otherwise
-     *      <code>IllegalArgumentException</code> is thrown)</li>
+     * <code>IllegalArgumentException</code> is thrown)</li>
      * </ul>
-     *
+     * 
      * @param n the size of the set
      * @param k the size of the subsets to be counted
      * @return <code>n choose k</code>
@@ -373,50 +161,72 @@
     public static double binomialCoefficientLog(final int n, final int k) {
         if (n < k) {
             throw new IllegalArgumentException(
-            "must have n >= k for binomial coefficient (n,k)");
+                "must have n >= k for binomial coefficient (n,k)");
         }
         if (n < 0) {
             throw new IllegalArgumentException(
-            "must have n >= 0 for binomial coefficient (n,k)");
+                "must have n >= 0 for binomial coefficient (n,k)");
         }
         if ((n == k) || (k == 0)) {
             return 0;
         }
         if ((k == 1) || (k == n - 1)) {
-            return Math.log((double) n);
+            return Math.log((double)n);
         }
         double logSum = 0;
-        
+
         // n!/k!
         for (int i = k + 1; i <= n; i++) {
-            logSum += Math.log((double) i);
+            logSum += Math.log((double)i);
         }
-        
+
         // divide by (n-k)!
         for (int i = 2; i <= n - k; i++) {
-            logSum -= Math.log((double) i);
+            logSum -= Math.log((double)i);
         }
-        
+
         return logSum;
     }
-    
+
     /**
-     * Returns n!.  Shorthand for <code>n</code>
-     * <a href="http://mathworld.wolfram.com/Factorial.html">
-     * Factorial</a>, the product of the numbers <code>1,...,n</code>.
-     *
+     * Returns the <a href="http://mathworld.wolfram.com/HyperbolicCosine.html">
+     * hyperbolic cosine</a> of x.
+     * 
+     * @param x double value for which to find the hyperbolic cosine
+     * @return hyperbolic cosine of x
+     */
+    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
+     * 
+     * @param x first value
+     * @param y second value
+     * @return true if the values are equal or both are NaN
+     */
+    public static boolean equals(double x, double y) {
+        return ((Double.isNaN(x) && Double.isNaN(y)) || x == y);
+    }
+
+    /**
+     * Returns n!. Shorthand for <code>n</code> <a
+     * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
+     * product of the numbers <code>1,...,n</code>.
      * <p>
-     * <Strong>Preconditions</strong>:<ul>
+     * <Strong>Preconditions</strong>:
+     * <ul>
      * <li> <code>n >= 0</code> (otherwise
-     *      <code>IllegalArgumentException</code> is thrown)</li>
-     * <li> The result is small enough to fit into a <code>long</code>.  The
-     *      largest value of <code>n</code> for which <code>n!</code>
-     *      < Long.MAX_VALUE</code> is 20.  If the computed value
-     *      exceeds <code>Long.MAX_VALUE</code> an <code>ArithMeticException
-     *      </code> is thrown.</li>
+     * <code>IllegalArgumentException</code> is thrown)</li>
+     * <li> The result is small enough to fit into a <code>long</code>. The
+     * largest value of <code>n</code> for which <code>n!</code> <
+     * Long.MAX_VALUE</code> is 20. If the computed value exceeds <code>Long.MAX_VALUE</code>
+     * an <code>ArithMeticException </code> is thrown.</li>
      * </ul>
      * </p>
-     *
+     * 
      * @param n argument
      * @return <code>n!</code>
      * @throws ArithmeticException if the result is too large to be represented
@@ -427,28 +237,27 @@
         long result = Math.round(factorialDouble(n));
         if (result == Long.MAX_VALUE) {
             throw new ArithmeticException(
-            "result too large to represent in a long integer");
+                "result too large to represent in a long integer");
         }
         return result;
     }
-    
+
     /**
-     * Returns n!.  Shorthand for <code>n</code>
-     * <a href="http://mathworld.wolfram.com/Factorial.html">
-     * Factorial</a>, the product of the numbers <code>1,...,n</code> as a
-     * <code>double</code>.
-     *
+     * Returns n!. Shorthand for <code>n</code> <a
+     * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
+     * product of the numbers <code>1,...,n</code> as a <code>double</code>.
      * <p>
-     * <Strong>Preconditions</strong>:<ul>
+     * <Strong>Preconditions</strong>:
+     * <ul>
      * <li> <code>n >= 0</code> (otherwise
-     *      <code>IllegalArgumentException</code> is thrown)</li>
-     * <li> The result is small enough to fit into a <code>double</code>.  The
-     *      largest value of <code>n</code> for which <code>n!</code>
-     *      < Double.MAX_VALUE</code> is 170.  If the computed value exceeds
-     *      Double.MAX_VALUE, Double.POSITIVE_INFINITY is returned</li>
+     * <code>IllegalArgumentException</code> is thrown)</li>
+     * <li> The result is small enough to fit into a <code>double</code>. The
+     * largest value of <code>n</code> for which <code>n!</code> <
+     * Double.MAX_VALUE</code> is 170. If the computed value exceeds
+     * Double.MAX_VALUE, Double.POSITIVE_INFINITY is returned</li>
      * </ul>
      * </p>
-     *
+     * 
      * @param n argument
      * @return <code>n!</code>
      * @throws IllegalArgumentException if n < 0
@@ -459,15 +268,16 @@
         }
         return Math.floor(Math.exp(factorialLog(n)) + 0.5);
     }
-    
+
     /**
      * Returns the natural logarithm of n!.
      * <p>
-     * <Strong>Preconditions</strong>:<ul>
+     * <Strong>Preconditions</strong>:
+     * <ul>
      * <li> <code>n >= 0</code> (otherwise
-     *      <code>IllegalArgumentException</code> is thrown)</li>
+     * <code>IllegalArgumentException</code> is thrown)</li>
      * </ul>
-     *
+     * 
      * @param n argument
      * @return <code>n!</code>
      * @throws IllegalArgumentException if preconditions are not met.
@@ -478,77 +288,21 @@
         }
         double logSum = 0;
         for (int i = 2; i <= n; i++) {
-            logSum += Math.log((double) i);
+            logSum += Math.log((double)i);
         }
         return logSum;
     }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/HyperbolicCosine.html">
-     * hyperbolic cosine</a> of x.
-     *
-     * @param x double value for which to find the hyperbolic cosine
-     * @return hyperbolic cosine of x
-     */
-    public static double cosh(double x) {
-        return (Math.exp(x) + Math.exp(-x)) / 2.0;
-    }
-    
-    /**
-     * Returns the <a href="http://mathworld.wolfram.com/HyperbolicSine.html">
-     * hyperbolic sine</a> of x.
-     *
-     * @param x double value for which to find the hyperbolic sine
-     * @return hyperbolic sine of x
-     */
-    public static double sinh(double x) {
-        return (Math.exp(x) - Math.exp(-x)) / 2.0;
-    }
-    
-    /**
-     * Returns an integer hash code representing the given double value.
-     *
-     * @param value  the value to be hashed
-     * @return the hash code
-     */
-    public static int hash(double value) {
-        long bits = Double.doubleToLongBits(value);
-        return (int)(bits ^ (bits >>> 32));
-    }
-    
-    /**
-     * Returns true iff both arguments are NaN or
-     * neither is NaN and they are equal
-     *
-     * @param x first value
-     * @param y second value
-     * @return true if the values are equal or both are NaN
-     */
-    public static boolean equals(double x, double y) {
-        return ((Double.isNaN(x) && Double.isNaN(y)) || x == y);
-    }
 
     /**
-     * Returns the least common multiple between two integer values.
+     * <p>
+     * Gets the greatest common divisor of the absolute value of two numbers,
+     * using the "binary gcd" method which avoids division and modulo
+     * operations. See Knuth 4.5.2 algorithm B. This algorithm is due to Josef
+     * Stein (1961).
+     * </p>
      * 
-     * @param a the first integer value.
-     * @param b the second integer value.
-     * @return the least common multiple between a and b.
-     * @throws ArithmeticException if the lcm is too large to store as an int
-     * @since 1.1
-     */
-    public static int lcm(int a, int b) {
-        return Math.abs(mulAndCheck(a / gcd(a, b) , b));
-    }
-
-    /**
-     * <p>Gets the greatest common divisor of the absolute value of
-     * two numbers, using the "binary gcd" method which avoids
-     * division and modulo operations.  See Knuth 4.5.2 algorithm B.
-     * This algorithm is due to Josef Stein (1961).</p>
-     *
-     * @param u  a non-zero number
-     * @param v  a non-zero number
+     * @param u a non-zero number
+     * @param v a non-zero number
      * @return the greatest common divisor, never zero
      * @since 1.1
      */
@@ -561,93 +315,421 @@
         // (i.e. we can't necessarily negate a negative number without
         // overflow)
         /* assert u!=0 && v!=0; */
-        if (u>0) { u=-u; } // make u negative
-        if (v>0) { v=-v; } // make v negative
+        if (u > 0) {
+            u = -u;
+        } // make u negative
+        if (v > 0) {
+            v = -v;
+        } // make v negative
         // B1. [Find power of 2]
-        int k=0;
-        while ((u&1)==0 && (v&1)==0 && k<31) { // while u and v are both even...
-            u/=2; v/=2; k++; // cast out twos.
+        int k = 0;
+        while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are
+                                                            // both even...
+            u /= 2;
+            v /= 2;
+            k++; // cast out twos.
         }
-        if (k==31) {
+        if (k == 31) {
             throw new ArithmeticException("overflow: gcd is 2^31");
         }
         // B2. Initialize: u and v have been divided by 2^k and at least
-        //     one is odd.
-        int t = ((u&1)==1) ? v : -(u/2)/*B3*/;
+        // one is odd.
+        int t = ((u & 1) == 1) ? v : -(u / 2)/* B3 */;
         // t negative: u was odd, v may be even (t replaces v)
         // t positive: u was even, v is odd (t replaces u)
         do {
             /* assert u<0 && v<0; */
             // B4/B3: cast out twos from t.
-            while ((t&1)==0) { // while t is even..
-                t/=2; // cast out twos
+            while ((t & 1) == 0) { // while t is even..
+                t /= 2; // cast out twos
             }
             // B5 [reset max(u,v)]
-            if (t>0) {
+            if (t > 0) {
                 u = -t;
             } else {
                 v = t;
             }
             // B6/B3. at this point both u and v should be odd.
-            t = (v - u)/2;
+            t = (v - u) / 2;
             // |u| larger: t positive (replace u)
             // |v| larger: t negative (replace v)
-        } while (t!=0);
-        return -u*(1<<k); // gcd is u*2^k
+        } while (t != 0);
+        return -u * (1 << k); // gcd is u*2^k
+    }
+
+    /**
+     * Returns an integer hash code representing the given double value.
+     * 
+     * @param value the value to be hashed
+     * @return the hash code
+     */
+    public static int hash(double value) {
+        long bits = Double.doubleToLongBits(value);
+        return (int)(bits ^ (bits >>> 32));
+    }
+
+    /**
+     * For a byte value x, this method returns (byte)(+1) if x >= 0 and
+     * (byte)(-1) if x < 0.
+     * 
+     * @param x the value, a byte
+     * @return (byte)(+1) or (byte)(-1), depending on the sign of x
+     */
+    public static byte indicator(final byte x) {
+        return (x >= ZB) ? PB : NB;
+    }
+
+    /**
+     * For a double precision value x, this method returns +1.0 if x >= 0 and
+     * -1.0 if x < 0. Returns <code>NaN</code> if <code>x</code> is
+     * <code>NaN</code>.
+     * 
+     * @param x the value, a double
+     * @return +1.0 or -1.0, depending on the sign of x
+     */
+    public static double indicator(final double x) {
+        if (Double.isNaN(x)) {
+            return Double.NaN;
+        }
+        return (x >= 0.0) ? 1.0 : -1.0;
+    }
+
+    /**
+     * For a float value x, this method returns +1.0F if x >= 0 and -1.0F if x <
+     * 0. Returns <code>NaN</code> if <code>x</code> is <code>NaN</code>.
+     * 
+     * @param x the value, a float
+     * @return +1.0F or -1.0F, depending on the sign of x
+     */
+    public static float indicator(final float x) {
+        if (Float.isNaN(x)) {
+            return Float.NaN;
+        }
+        return (x >= 0.0F) ? 1.0F : -1.0F;
+    }
+
+    /**
+     * For an int value x, this method returns +1 if x >= 0 and -1 if x < 0.
+     * 
+     * @param x the value, an int
+     * @return +1 or -1, depending on the sign of x
+     */
+    public static int indicator(final int x) {
+        return (x >= 0) ? 1 : -1;
     }
 
-    /** 
+    /**
+     * For a long value x, this method returns +1L if x >= 0 and -1L if x < 0.
+     * 
+     * @param x the value, a long
+     * @return +1L or -1L, depending on the sign of x
+     */
+    public static long indicator(final long x) {
+        return (x >= 0L) ? 1L : -1L;
+    }
+
+    /**
+     * For a short value x, this method returns (short)(+1) if x >= 0 and
+     * (short)(-1) if x < 0.
+     * 
+     * @param x the value, a short
+     * @return (short)(+1) or (short)(-1), depending on the sign of x
+     */
+    public static short indicator(final short x) {
+        return (x >= ZS) ? PS : NS;
+    }
+
+    /**
+     * Returns the least common multiple between two integer values.
+     * 
+     * @param a the first integer value.
+     * @param b the second integer value.
+     * @return the least common multiple between a and b.
+     * @throws ArithmeticException if the lcm is too large to store as an int
+     * @since 1.1
+     */
+    public static int lcm(int a, int b) {
+        return Math.abs(mulAndCheck(a / gcd(a, b), b));
+    }
+
+    /**
      * Multiply two integers, checking for overflow.
      * 
      * @param x a factor
      * @param y a factor
      * @return the product <code>x*y</code>
-     * @throws ArithmeticException if the result can not be represented as
-     *                             an int
+     * @throws ArithmeticException if the result can not be represented as an
+     *         int
      * @since 1.1
      */
     public static int mulAndCheck(int x, int y) {
-        long m = ((long)x)*((long)y);
-        if (m < Integer.MIN_VALUE ||
-                m > Integer.MAX_VALUE) {
+        long m = ((long)x) * ((long)y);
+        if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
             throw new ArithmeticException("overflow: mul");
         }
         return (int)m;
     }
-    
-    /** 
-     * Add two integers, checking for overflow.
+
+    /**
+     * Round the given value to the specified number of decimal places. The
+     * value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
      * 
-     * @param x an addend
-     * @param y an addend
-     * @return the sum <code>x+y</code>
-     * @throws ArithmeticException if the result can not be represented as
-     * an int
+     * @param x the value to round.
+     * @param scale the number of digits to the right of the decimal point.
+     * @return the rounded value.
      * @since 1.1
      */
-    public static int addAndCheck(int x, int y) {
-        long s = (long)x+(long)y;
-        if (s < Integer.MIN_VALUE ||
-                s > Integer.MAX_VALUE) {
-            throw new ArithmeticException("overflow: add");
+    public static double round(double x, int scale) {
+        return round(x, scale, BigDecimal.ROUND_HALF_UP);
+    }
+
+    /**
+     * Round the given value to the specified number of decimal places. The
+     * value is rounded using the given method which is any method defined in
+     * {@link BigDecimal}.
+     * 
+     * @param x the value to round.
+     * @param scale the number of digits to the right of the decimal point.
+     * @param roundingMethod the rounding method as defined in
+     *        {@link BigDecimal}.
+     * @return the rounded value.
+     * @since 1.1
+     */
+    public static double round(double x, int scale, int roundingMethod) {
+        double sign = sign(x);
+        double factor = Math.pow(10.0, scale) * sign;
+        return roundUnscaled(x * factor, sign, roundingMethod) / factor;
+    }
+
+    /**
+     * Round the given value to the specified number of decimal places. The
+     * value is rounding using the {@link BigDecimal#ROUND_HALF_UP} method.
+     * 
+     * @param x the value to round.
+     * @param scale the number of digits to the right of the decimal point.
+     * @return the rounded value.
+     * @since 1.1
+     */
+    public static float round(float x, int scale) {
+        return round(x, scale, BigDecimal.ROUND_HALF_UP);
+    }
+
+    /**
+     * Round the given value to the specified number of decimal places. The
+     * value is rounded using the given method which is any method defined in
+     * {@link BigDecimal}.
+     * 
+     * @param x the value to round.
+     * @param scale the number of digits to the right of the decimal point.
+     * @param roundingMethod the rounding method as defined in
+     *        {@link BigDecimal}.
+     * @return the rounded value.
+     * @since 1.1
+     */
+    public static float round(float x, int scale, int roundingMethod) {
+        float sign = sign(x);
+        float factor = (float)Math.pow(10.0f, scale) * sign;
+        return (float)roundUnscaled(x * factor, sign, roundingMethod) / factor;
+    }
+
+    /**
+     * Round the given non-negative, value to the "nearest" integer. Nearest is
+     * determined by the rounding method specified. Rounding methods are defined
+     * in {@link BigDecimal}.
+     * 
+     * @param unscaled the value to round.
+     * @param sign the sign of the original, scaled value.
+     * @param roundingMethod the rounding method as defined in
+     *        {@link BigDecimal}.
+     * @return the rounded value.
+     * @since 1.1
+     */
+    private static double roundUnscaled(double unscaled, double sign,
+        int roundingMethod) {
+        switch (roundingMethod) {
+        case BigDecimal.ROUND_CEILING :
+            if (sign == -1) {
+                unscaled = Math.floor(unscaled);
+            } else {
+                unscaled = Math.ceil(unscaled);
+            }
+            break;
+        case BigDecimal.ROUND_DOWN :
+            unscaled = Math.floor(unscaled);
+            break;
+        case BigDecimal.ROUND_FLOOR :
+            if (sign == -1) {
+                unscaled = Math.ceil(unscaled);
+            } else {
+                unscaled = Math.floor(unscaled);
+            }
+            break;
+        case BigDecimal.ROUND_HALF_DOWN : {
+            double fraction = Math.abs(unscaled - Math.floor(unscaled));
+            if (fraction > 0.5) {
+                unscaled = Math.ceil(unscaled);
+            } else {
+                unscaled = Math.floor(unscaled);
+            }
+            break;
         }
-        return (int)s;
+        case BigDecimal.ROUND_HALF_EVEN : {
+            double fraction = Math.abs(unscaled - Math.floor(unscaled));
+            if (fraction > 0.5) {
+                unscaled = Math.ceil(unscaled);
+            } else if (fraction < 0.5) {
+                unscaled = Math.floor(unscaled);
+            } else {
+                if (Math.floor(unscaled) / 2.0 == Math.floor(Math
+                    .floor(unscaled) / 2.0)) { // even
+                    unscaled = Math.floor(unscaled);
+                } else { // odd
+                    unscaled = Math.ceil(unscaled);
+                }
+            }
+            break;
+        }
+        case BigDecimal.ROUND_HALF_UP : {
+            double fraction = Math.abs(unscaled - Math.floor(unscaled));
+            if (fraction >= 0.5) {
+                unscaled = Math.ceil(unscaled);
+            } else {
+                unscaled = Math.floor(unscaled);
+            }
+            break;
+        }
+        case BigDecimal.ROUND_UNNECESSARY :
+            if (unscaled != Math.floor(unscaled)) {
+                throw new ArithmeticException("Inexact result from rounding");
+            }
+            break;
+        case BigDecimal.ROUND_UP :
+            unscaled = Math.ceil(unscaled);
+            break;
+        default :
+            throw new IllegalArgumentException("Invalid rounding method.");
+        }
+        return unscaled;
+    }
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/Sign.html"> sign</a>
+     * for byte value <code>x</code>.
+     * <p>
+     * For a byte value x, this method returns (byte)(+1) if x > 0, (byte)(0) if
+     * x = 0, and (byte)(-1) if x < 0.
+     * 
+     * @param x the value, a byte
+     * @return (byte)(+1), (byte)(0), or (byte)(-1), depending on the sign of x
+     */
+    public static byte sign(final byte x) {
+        return (x == ZB) ? ZB : (x > ZB) ? PB : NB;
     }
-    
-    /** 
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/Sign.html"> sign</a>
+     * for double precision <code>x</code>.
+     * <p>
+     * For a double value <code>x</code>, this method returns
+     * <code>+1.0</code> if <code>x > 0</code>, <code>0.0</code> if
+     * <code>x = 0.0</code>, and <code>-1.0</code> if <code>x < 0</code>.
+     * Returns <code>NaN</code> if <code>x</code> is <code>NaN</code>.
+     * 
+     * @param x the value, a double
+     * @return +1.0, 0.0, or -1.0, depending on the sign of x
+     */
+    public static double sign(final double x) {
+        if (Double.isNaN(x)) {
+            return Double.NaN;
+        }
+        return (x == 0.0) ? 0.0 : (x > 0.0) ? 1.0 : -1.0;
+    }
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/Sign.html"> sign</a>
+     * for float value <code>x</code>.
+     * <p>
+     * For a float value x, this method returns +1.0F if x > 0, 0.0F if x =
+     * 0.0F, and -1.0F if x < 0. Returns <code>NaN</code> if <code>x</code>
+     * is <code>NaN</code>.
+     * 
+     * @param x the value, a float
+     * @return +1.0F, 0.0F, or -1.0F, depending on the sign of x
+     */
+    public static float sign(final float x) {
+        if (Float.isNaN(x)) {
+            return Float.NaN;
+        }
+        return (x == 0.0F) ? 0.0F : (x > 0.0F) ? 1.0F : -1.0F;
+    }
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/Sign.html"> sign</a>
+     * for int value <code>x</code>.
+     * <p>
+     * For an int value x, this method returns +1 if x > 0, 0 if x = 0, and -1
+     * if x < 0.
+     * 
+     * @param x the value, an int
+     * @return +1, 0, or -1, depending on the sign of x
+     */
+    public static int sign(final int x) {
+        return (x == 0) ? 0 : (x > 0) ? 1 : -1;
+    }
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/Sign.html"> sign</a>
+     * for long value <code>x</code>.
+     * <p>
+     * For a long value x, this method returns +1L if x > 0, 0L if x = 0, and
+     * -1L if x < 0.
+     * 
+     * @param x the value, a long
+     * @return +1L, 0L, or -1L, depending on the sign of x
+     */
+    public static long sign(final long x) {
+        return (x == 0L) ? 0L : (x > 0L) ? 1L : -1L;
+    }
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/Sign.html"> sign</a>
+     * for short value <code>x</code>.
+     * <p>
+     * For a short value x, this method returns (short)(+1) if x > 0, (short)(0)
+     * if x = 0, and (short)(-1) if x < 0.
+     * 
+     * @param x the value, a short
+     * @return (short)(+1), (short)(0), or (short)(-1), depending on the sign of
+     *         x
+     */
+    public static short sign(final short x) {
+        return (x == ZS) ? ZS : (x > ZS) ? PS : NS;
+    }
+
+    /**
+     * Returns the <a href="http://mathworld.wolfram.com/HyperbolicSine.html">
+     * hyperbolic sine</a> of x.
+     * 
+     * @param x double value for which to find the hyperbolic sine
+     * @return hyperbolic sine of x
+     */
+    public static double sinh(double x) {
+        return (Math.exp(x) - Math.exp(-x)) / 2.0;
+    }
+
+    /**
      * Subtract two integers, checking for overflow.
      * 
      * @param x the minuend
      * @param y the subtrahend
      * @return the difference <code>x-y</code>
-     * @throws ArithmeticException if the result can not be represented as
-     * an int
+     * @throws ArithmeticException if the result can not be represented as an
+     *         int
      * @since 1.1
      */
     public static int subAndCheck(int x, int y) {
-        long s = (long)x-(long)y;
-        if (s < Integer.MIN_VALUE ||
-                s > Integer.MAX_VALUE) {
+        long s = (long)x - (long)y;
+        if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
             throw new ArithmeticException("overflow: add");
         }
         return (int)s;

Modified: jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java?rev=231029&r1=231028&r2=231029&view=diff
==============================================================================
--- jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java (original)
+++ jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java Tue Aug  9 06:10:26 2005
@@ -32,9 +32,6 @@
         super(name);
     }
 
-    public void setUp() {
-    }
-
     public static Test suite() {
         TestSuite suite = new TestSuite(MathUtilsTest.class);
         suite.setName("MathUtils Tests");
@@ -471,13 +468,11 @@
             // expected
         }
     }
-    
     public void testRoundFloat() {
         float x = 1.234567890f;
-        assertEquals(1.23f, MathUtils.round(x, 2), 0.0f);
-        assertEquals(1.235f, MathUtils.round(x, 3), 0.0f);
-        assertEquals(1.2346f, MathUtils.round(x, 4), 0.0f);
-        
+        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);
@@ -487,10 +482,80 @@
         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.23f, MathUtils.round(x, 2, BigDecimal.ROUND_DOWN), 0.0f);
-        assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_DOWN), 0.0f);
-        assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_DOWN), 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
+        }
     }
     
     public void testRoundDouble() {
@@ -507,9 +572,79 @@
         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);
+        assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(-1.234, MathUtils.round(-x, 3, BigDecimal.ROUND_CEILING), 0.0);
+        assertEquals(-1.2345, MathUtils.round(-x, 4, BigDecimal.ROUND_CEILING), 0.0);
 
         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_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);
+        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);
+        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);
+        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);
+        assertEquals(1.234, MathUtils.round(1.2345, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
+        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);
+        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);
+        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();
+        } catch (IllegalArgumentException ex) {
+            // success
+        }
     }
 }

Modified: jakarta/commons/proper/math/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/changes.xml?rev=231029&r1=231028&r2=231029&view=diff
==============================================================================
--- jakarta/commons/proper/math/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/math/trunk/xdocs/changes.xml Tue Aug  9 06:10:26 2005
@@ -45,6 +45,10 @@
        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.">
+      <action dev="brentworden" type="fix" issue="35904"  due-to="Srinivas Vemury">
+        Changed rounding methods to not rely on BigDecimal conversions which
+		was causing numerical error.
+      </action>
       <action dev="psteitz" type="fix" issue="35434"  due-to="Jörg Weimar">
         Changed Fraction(double) to correctly handle near-integral arguments.
       </action>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org