From 4eb8044ae73cacd278330b07795bdd649a82fc30 Mon Sep 17 00:00:00 2001
From: Brent Worden
- * For a double value
- * 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
- * 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
- * sign for short value
- * 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
- * sign for int value
- * 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
- * sign for long value
- * 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
- * Preconditions:
- * Preconditions:
- * Preconditions:
- * Preconditions:x+y
+ * @throws ArithmeticException if the result can not be represented as an
+ * int
* @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);
+ 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 (int)s;
}
/**
- * 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) {
- return (new BigDecimal(new Float(x).toString()).setScale(scale, roundingMethod)).floatValue();
- }
-
- /**
- * Returns the
- * sign for double precision x
.
- *
+ * Returns an exact representation of the Binomial
+ * Coefficient, "n choose k
", the number of
+ * k
-element subsets that can be selected from an
+ * n
-element set.
* x
, this method returns +1.0
- * if x > 0
, 0.0
if x = 0.0
,
- * and -1.0
if x < 0
. Returns NaN
- * if x
is NaN
.
- *
- * @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
- * sign for float value x
.
- *
- * NaN
- * if x
is NaN
.
- *
- * @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
- * sign for byte value x
.
- *
- * x
.
- *
- * x
.
- *
- * x
.
- *
- * NaN
- * if x
is NaN
.
- *
- * @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 NaN
- * if x
is NaN
.
- *
- * @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 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;
- }
-
- /**
- * Returns an exact representation of the
- *
- * Binomial Coefficient, "n choose k
",
- * the number of k
-element subsets that can be selected from
- * an n
-element set.
- *
+ * Preconditions:
+ *
*
- *
+ *
* @param n the size of the set
* @param k the size of the subsets to be counted
* @return 0 <= k <= n
(otherwise
- * IllegalArgumentException
is thrown)long
. The
- * largest value of n
for which all coefficients are
- * < Long.MAX_VALUE
is 66. If the computed value
- * exceeds Long.MAX_VALUE
an ArithMeticException
- *
is thrown.IllegalArgumentException
is thrown)
+ * long
. The
+ * largest value of n
for which all coefficients are
+ * < Long.MAX_VALUE
is 66. If the computed value exceeds
+ * Long.MAX_VALUE
an ArithMeticException
+ *
is
+ * thrown.n choose k
@@ -307,11 +93,11 @@ public final class MathUtils {
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 @@ public final class MathUtils {
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 double
representation of the
- *
- * Binomial Coefficient, "n choose k
",
- * the number of k
-element subsets that can be selected from
- * an n
-element set.
+ * Returns a double
representation of the Binomial
+ * Coefficient, "n choose k
", the number of
+ * k
-element subsets that can be selected from an
+ * n
-element set.
*
+ * Preconditions:
+ *
*
- *
+ *
* @param n the size of the set
* @param k the size of the subsets to be counted
* @return 0 <= k <= n
(otherwise
- * IllegalArgumentException
is thrown)double
.
- * The largest value of n
for which all coefficients are
- * < Double.MAX_VALUE is 1029. If the computed value exceeds
- * Double.MAX_VALUE, Double.POSITIVE_INFINITY is returnedIllegalArgumentException
is thrown)
+ * double
. The
+ * largest value of n
for which all coefficients are <
+ * Double.MAX_VALUE is 1029. If the computed value exceeds Double.MAX_VALUE,
+ * Double.POSITIVE_INFINITY is returnedn choose k
@@ -352,19 +139,20 @@ public final class MathUtils {
public static double binomialCoefficientDouble(final int n, final int k) {
return Math.floor(Math.exp(binomialCoefficientLog(n, k)) + 0.5);
}
-
+
/**
- * Returns the natural log
of the
- *
- * Binomial Coefficient, "n choose k
",
- * the number of k
-element subsets that can be selected from
- * an n
-element set.
+ * Returns the natural log
of the Binomial
+ * Coefficient, "n choose k
", the number of
+ * k
-element subsets that can be selected from an
+ * n
-element set.
*
+ * Preconditions:
+ *
*
- *
+ *
* @param n the size of the set
* @param k the size of the subsets to be counted
* @return 0 <= k <= n
(otherwise
- * IllegalArgumentException
is thrown)IllegalArgumentException
is thrown)
* n choose k
@@ -373,50 +161,72 @@ public final class MathUtils {
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 n
- *
- * Factorial, the product of the numbers 1,...,n
.
- *
+ * Returns the
+ * hyperbolic cosine 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 n
Factorial, the
+ * product of the numbers 1,...,n
.
*
+ * Preconditions:
+ *
*
* n >= 0
(otherwise
- * IllegalArgumentException
is thrown)long
. The
- * largest value of n
for which n!
- * < Long.MAX_VALUE is 20. If the computed value
- * exceeds Long.MAX_VALUE
an ArithMeticException
- *
is thrown.IllegalArgumentException
is thrown)
+ * long
. The
+ * largest value of n
for which n!
<
+ * Long.MAX_VALUE is 20. If the computed value exceeds Long.MAX_VALUE
+ * an ArithMeticException
is thrown.
n!
* @throws ArithmeticException if the result is too large to be represented
@@ -427,28 +237,27 @@ public final class MathUtils {
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 n
- *
- * Factorial, the product of the numbers 1,...,n
as a
- * double
.
- *
+ * Returns n!. Shorthand for n
Factorial, the
+ * product of the numbers 1,...,n
as a double
.
* - * Preconditions:
n >= 0
(otherwise
- * IllegalArgumentException
is thrown)double
. The
- * largest value of n
for which n!
- * < Double.MAX_VALUE is 170. If the computed value exceeds
- * Double.MAX_VALUE, Double.POSITIVE_INFINITY is returnedIllegalArgumentException
is thrown)
+ * double
. The
+ * largest value of n
for which n!
<
+ * Double.MAX_VALUE is 170. If the computed value exceeds
+ * Double.MAX_VALUE, Double.POSITIVE_INFINITY is returnedn!
* @throws IllegalArgumentException if n < 0
@@ -459,15 +268,16 @@ public final class MathUtils {
}
return Math.floor(Math.exp(factorialLog(n)) + 0.5);
}
-
+
/**
* Returns the natural logarithm of n!.
* - * Preconditions:
n >= 0
(otherwise
- * IllegalArgumentException
is thrown)IllegalArgumentException
is thrown)
* n!
* @throws IllegalArgumentException if preconditions are not met.
@@ -478,77 +288,21 @@ public final class MathUtils {
}
double logSum = 0;
for (int i = 2; i <= n; i++) {
- logSum += Math.log((double) i);
+ logSum += Math.log((double)i);
}
return logSum;
}
-
- /**
- * Returns the
- * hyperbolic cosine 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
- * hyperbolic sine 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.
+ * + * 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). + *
* - * @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)); - } - - /** - *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).
- * - * @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 @@ public final class MathUtils { // (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<NaN
if x
is
+ * NaN
.
+ *
+ * @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 NaN
if x
is NaN
.
+ *
+ * @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 x*y
- * @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 x+y
- * @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");
- }
- return (int)s;
+ 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;
+ }
+ 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 sign
+ * for byte value x
.
+ *
+ * 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 sign
+ * for double precision x
.
+ *
+ * For a double value x
, this method returns
+ * +1.0
if x > 0
, 0.0
if
+ * x = 0.0
, and -1.0
if x < 0
.
+ * Returns NaN
if x
is NaN
.
+ *
+ * @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 sign
+ * for float value x
.
+ *
+ * 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 NaN
if x
+ * is NaN
.
+ *
+ * @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 sign
+ * for int value x
.
+ *
+ * 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 sign
+ * for long value x
.
+ *
+ * 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 sign
+ * for short value x
.
+ *
+ * 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
+ * hyperbolic sine 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 x-y
- * @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;
diff --git a/src/test/org/apache/commons/math/util/MathUtilsTest.java b/src/test/org/apache/commons/math/util/MathUtilsTest.java
index f3fb1493a..563a94833 100644
--- a/src/test/org/apache/commons/math/util/MathUtilsTest.java
+++ b/src/test/org/apache/commons/math/util/MathUtilsTest.java
@@ -32,9 +32,6 @@ public final class MathUtilsTest extends TestCase {
super(name);
}
- public void setUp() {
- }
-
public static Test suite() {
TestSuite suite = new TestSuite(MathUtilsTest.class);
suite.setName("MathUtils Tests");
@@ -471,13 +468,11 @@ public final class MathUtilsTest extends TestCase {
// 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 @@ public final class MathUtilsTest extends TestCase {
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.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.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 @@ public final class MathUtilsTest extends TestCase {
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
+ }
}
}
\ No newline at end of file
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index 46541b9bd..6cfd9f1bf 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -45,6 +45,10 @@ Commons Math Release Notes
and numerical utilities, and a PRNG pluggability framework making it
possible to replace the JDK-supplied random number generator in
commons-math (and elsewhere) with alternative PRNG implementations.">
+