sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1394562 - in /sis/branches/JDK6: ./ sis-utility/src/main/java/org/apache/sis/math/ sis-utility/src/main/java/org/apache/sis/util/resources/ sis-utility/src/test/java/org/apache/sis/math/ sis-utility/src/test/java/org/apache/sis/test/suite/
Date Fri, 05 Oct 2012 15:02:24 GMT
Author: desruisseaux
Date: Fri Oct  5 15:02:23 2012
New Revision: 1394562

URL: http://svn.apache.org/viewvc?rev=1394562&view=rev
Log:
Initial commit of MathFunctions.

Added:
    sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/
    sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java   (with props)
    sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java   (with props)
    sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/
    sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java   (with props)
Modified:
    sis/branches/JDK6/pom.xml
    sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Modified: sis/branches/JDK6/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/pom.xml?rev=1394562&r1=1394561&r2=1394562&view=diff
==============================================================================
--- sis/branches/JDK6/pom.xml (original)
+++ sis/branches/JDK6/pom.xml Fri Oct  5 15:02:23 2012
@@ -471,7 +471,7 @@ Apache SIS is a toolkit for describing l
             </group>
             <group>
               <title>Utilities</title>
-              <packages>org.apache.sis.io*:org.apache.sis.util*</packages>
+              <packages>org.apache.sis.math*:org.apache.sis.util*:org.apache.sis.io*</packages>
             </group>
           </groups>
 

Added: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java?rev=1394562&view=auto
==============================================================================
--- sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java (added)
+++ sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java Fri Oct  5 15:02:23 2012
@@ -0,0 +1,703 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.math;
+
+import java.util.Arrays;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.Workaround;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+
+import static java.lang.Float.intBitsToFloat;
+import static java.lang.Float.floatToRawIntBits;
+import static java.lang.Double.longBitsToDouble;
+import static java.lang.Double.doubleToRawLongBits;
+import static org.apache.sis.util.Arrays.resize;
+import static org.apache.sis.util.Arrays.isSorted;
+import static org.apache.sis.util.Arrays.EMPTY_INT;
+
+
+/**
+ * Simple mathematical functions in addition to the ones provided in {@link Math}.
+ * Some methods in this class are very similar to the standard {@link Math} methods
+ * or could be implemented with straightforward formulas.
+ * However the methods in this class put an emphasis on:
+ * <p>
+ * <ul>
+ *   <li>Rounding errors: {@link #magnitude(double[])}, {@link #pow10(double)}.</li>
+ *   <li>Distinguishing positive zero from negative zero: {@link #isPositive(double)},
+ *       {@link #isNegative(double)}, {@link #isSameSign(double, double)},
+ *       {@link #xorSign(double, double)}.</li>
+ *   <li>Distinguishing the different kinds of NaN numbers: {@link #toNanFloat(int)},
+ *       {@link #toNanOrdinal(float)}.</li>
+ * </ul>
+ * <p>
+ * Additional functions not found in {@code Math} are: {@link #atanh(double)}.
+ *
+ * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
+ * @since   0.3 (derived from geotk-1.0)
+ * @version 0.3
+ * @module
+ */
+public final class MathFunctions extends Static {
+    /**
+     * The square root of 2, which is {@value}.
+     *
+     * @see Math#sqrt(double)
+     */
+    public static final double SQRT_2 = 1.4142135623730951;
+
+    /**
+     * Table of some integer powers of 10. Used for faster computation in {@link #pow10(int)}.
+     *
+     * @see #pow10(int)
+     */
+    private static final double[] POW10 = {
+        1E+00, 1E+01, 1E+02, 1E+03, 1E+04, 1E+05, 1E+06, 1E+07, 1E+08, 1E+09,
+        1E+10, 1E+11, 1E+12, 1E+13, 1E+14, 1E+15, 1E+16, 1E+17, 1E+18, 1E+19,
+        1E+20, 1E+21, 1E+22
+        // Do not add more elements, unless we verified that 1/x is accurate.
+        // Last time we tried, it was not accurate anymore starting at 1E+23.
+    };
+
+    /**
+     * Bit mask to isolate the sign bit of non-{@linkplain Double#isNaN(double) NaN} values in a
+     * {@code double}. For any real value, the following code evaluate to 0 if the given value is
+     * positive:
+     *
+     * {@preformat java
+     *     Double.doubleToRawLongBits(value) & SIGN_BIT_MASK;
+     * }
+     *
+     * Note that this idiom differentiates positive zero from negative zero.
+     * It should be used only when such difference matter.
+     *
+     * @see #isPositive(double)
+     * @see #isNegative(double)
+     * @see #isSameSign(double, double)
+     * @see #xorSign(double, double)
+     */
+    private static final long SIGN_BIT_MASK = Long.MIN_VALUE;
+
+    /**
+     * The minimal ordinal value for {@code NaN} numbers created by {@link #toNanFloat(int)}.
+     *
+     * @see #toNanFloat(int)
+     * @see #toNanOrdinal(float)
+     */
+    private static final int MIN_NAN_ORDINAL = -0x200000;
+
+    /**
+     * The maximal ordinal value for {@code NaN} numbers created by {@link #toNanFloat(int)}.
+     *
+     * @see #toNanFloat(int)
+     * @see #toNanOrdinal(float)
+     */
+    static final int MAX_NAN_ORDINAL = 0x1FFFFF;
+
+    /**
+     * The highest prime number supported by the {@link #nextPrimeNumber(int)} method.
+     * In the current implementation, this value is {@value}. However this limit may
+     * change in any future Apache SIS version.
+     *
+     * {@note The current value is the highest prime number representable as an unsigned 16 bits
+     * integer. This is enough for current needs because 16 bits prime numbers are sufficient for
+     * finding the divisors of any 32 bits integers.}
+     *
+     * @see #nextPrimeNumber(int)
+     */
+    public static final int HIGHEST_SUPPORTED_PRIME_NUMBER = 65521;
+
+    /**
+     * Maximal length needed for the {@link #primes} array in order to store prime numbers
+     * from 2 to 32749 (15 bits) or {@value #HIGHEST_SUPPORTED_PRIME_NUMBER} (16 bits).
+     *
+     * @see #primeNumberAt(int)
+     */
+    static final int PRIMES_LENGTH_15_BITS = 3512,
+                     PRIMES_LENGTH_16_BITS = 6542;
+
+    /**
+     * The sequence of prime numbers computed so far. Will be expanded as needed.
+     * We limit ourself to 16 bits numbers because they are sufficient for computing
+     * divisors of any 32 bits number.
+     *
+     * @see #primeNumberAt(int)
+     */
+    private static volatile short[] primes = new short[] {2, 3};
+
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private MathFunctions() {
+    }
+
+    /**
+     * Returns the magnitude of the given vector. This is defined by:
+     *
+     * {@preformat math
+     *     sqrt(vector[0]² + vector[1]² + … + vector[length-1]²)
+     * }
+     *
+     * {@section Implementation note}
+     * In the special case where only one element is different than zero, this method
+     * returns directly the {@linkplain Math#abs(double) absolute value} of that element
+     * without computing {@code sqrt(v²)}, in order to avoid rounding error. This special case
+     * has been implemented because this method is often invoked for computing the length of
+     * {@linkplain org.opengis.coverage.grid.RectifiedGrid#getOffsetVectors() offset vectors},
+     * typically aligned with the axes of a {@linkplain org.opengis.referencing.cs.CartesianCS
+     * Cartesian coordinate system}.
+     *
+     * @param  vector The vector for which to compute the magnitude.
+     * @return The magnitude of the given vector.
+     *
+     * @see Math#hypot(double, double)
+     */
+    public static double magnitude(final double... vector) {
+        int i = vector.length;
+
+        // If every elements in the array are zero, returns zero.
+        double sum;
+        do if (i == 0) return 0;
+        while ((sum = vector[--i]) == 0);
+
+        // We have found a non-zero element. If it is the only one, returns it directly.
+        double v;
+        do if (i == 0) return Math.abs(sum);
+        while ((v = vector[--i]) == 0);
+
+        // If there is exactly 2 elements, use Math.hypot which is more robust than our algorithm.
+        double v2;
+        do if (i == 0) return Math.hypot(sum, v);
+        while ((v2 = vector[--i]) == 0);
+
+        // Usual magnitude computation.
+        sum = sum*sum + v*v + v2*v2;
+        while (i != 0) {
+            v = vector[--i];
+            sum += v*v;
+        }
+        return Math.sqrt(sum);
+    }
+
+    /**
+     * Computes 10 raised to the power of <var>x</var>. This method delegates to
+     * <code>{@linkplain #pow10(int) pow10}((int) x)</code> if <var>x</var> is an
+     * integer, or to <code>{@linkplain Math#pow(double, double) Math.pow}(10, x)</code>
+     * otherwise.
+     *
+     * @param x The exponent.
+     * @return 10 raised to the given exponent.
+     *
+     * @see #pow10(int)
+     * @see Math#pow(double, double)
+     */
+    public static double pow10(final double x) {
+        final int ix = (int) x;
+        if (ix == x) {
+            return pow10(ix);
+        } else {
+            return Math.pow(10, x);
+        }
+    }
+
+    /**
+     * Computes 10 raised to the power of <var>x</var>. This method tries to be slightly more
+     * accurate than <code>{@linkplain Math#pow(double, double) Math.pow}(10,x)</code>,
+     * sometime at the cost of performance.
+     * <p>
+     * The {@code Math.pow(10,x)} method doesn't always return the closest IEEE floating point
+     * representation. More accurate calculations are slower and usually not necessary, but the
+     * base 10 is a special case since it is used for scaling axes or formatting human-readable
+     * output, in which case the precision may matter.
+     *
+     * @param x The exponent.
+     * @return 10 raised to the given exponent.
+     */
+    @Workaround(library="JDK", version="1.4")
+    public static double pow10(final int x) {
+        if (x >= 0) {
+            if (x < POW10.length) {
+                return POW10[x];
+            }
+        } else if (x != Integer.MIN_VALUE) {
+            final int nx = -x;
+            if (nx < POW10.length) {
+                return 1 / POW10[nx];
+            }
+        }
+        try {
+            /*
+             * Double.parseDouble("1E"+x) gives as good or better numbers than Math.pow(10,x)
+             * for ALL integer powers, but is slower. We hope that the current workaround is only
+             * temporary. See http://developer.java.sun.com/developer/bugParade/bugs/4358794.html
+             */
+            return Double.parseDouble("1E" + x);
+        } catch (NumberFormatException exception) {
+            return StrictMath.pow(10, x);
+        }
+    }
+
+    /**
+     * Returns the inverse hyperbolic tangent of the given value.
+     * This is the inverse of the {@linkplain Math#tanh(double) tanh} method.
+     * The range of input values shall be in the [-1 … 1].
+     * <p>
+     * Special cases:
+     * </ul>
+     *   <li>For <var>x</var> = NaN, this method returns a {@linkplain Double#isNaN(double) NaN} value.</li>
+     *   <li>For <var>x</var> = -1, this method returns {@linkplain Double#NEGATIVE_INFINITY negative infinity}.</li>
+     *   <li>For <var>x</var> = +1, this method returns {@linkplain Double#POSITIVE_INFINITY positive infinity}.</li>
+     * </ul>
+     *
+     * @param  x The value for which to compute the inverse hyperbolic tangent.
+     * @return The inverse hyperbolic tangent of the given value.
+     *
+     * @see Math#tanh(double)
+     */
+    public static double atanh(final double x) {
+        /*
+         * The classical formulas is log((1+x)/(1-x))/2, but the following is more
+         * accurate if the (1+x)/(1-x) ratio is close to 1, i.e. if x is close to 0.
+         */
+        return 0.5 * Math.log1p(2*x / (1-x));
+    }
+
+    /**
+     * Returns {@code true} if the given value is positive, <em>excluding</em> negative zero.
+     * <p>
+     * Special cases:
+     * <ul>
+     *   <li>If the value is {@code +0.0}, returns {@code true}</li>
+     *   <li>If the value is {@code -0.0}, returns <b>{@code false}</b></li>
+     *   <li>If the value is {@link Double#isNaN(double) NaN}, returns {@code false}</li>
+     * </ul>
+     * <p>
+     * As seen from the above cases, this method distinguishes positive zero from negative zero.
+     * The handling of zero values is the difference between invoking {@code isPositive(double)}
+     * and testing if (<var>value</var> &gt;= 0).
+     *
+     * @param  value The value to test.
+     * @return {@code true} if the given value is positive, excluding negative zero.
+     */
+    public static boolean isPositive(final double value) {
+        return (doubleToRawLongBits(value) & SIGN_BIT_MASK) == 0 && !Double.isNaN(value);
+    }
+
+    /**
+     * Returns {@code true} if the given value is negative, <em>including</em> negative zero.
+     * <p>
+     * Special cases:
+     * <ul>
+     *   <li>If the value is {@code +0.0}, returns {@code false}</li>
+     *   <li>If the value is {@code -0.0}, returns <b>{@code true}</b></li>
+     *   <li>If the value is {@link Double#isNaN(double) NaN}, returns {@code false}</li>
+     * </ul>
+     * <p>
+     * As seen from the above cases, this method distinguishes positive zero from negative zero.
+     * The handling of zero values is the difference between invoking {@code isNegative(double)}
+     * and testing if (<var>value</var> &lt; 0).
+     *
+     * @param  value The value to test.
+     * @return {@code true} if the given value is negative, including negative zero.
+     */
+    public static boolean isNegative(final double value) {
+        return (doubleToRawLongBits(value) & SIGN_BIT_MASK) != 0 && !Double.isNaN(value);
+    }
+
+    /**
+     * Returns {@code true} if the given values have the same sign, differentiating positive
+     * and negative zeros.
+     * <p>
+     * Special cases:
+     * <ul>
+     *   <li>{@code +0.0} and {@code -0.0} are considered to have opposite sign</li>
+     *   <li>If any value is {@link Double#isNaN(double) NaN}, returns {@code false}</li>
+     * </ul>
+     * <p>
+     *
+     * @param  v1 The first value.
+     * @param  v2 The second value, to compare the sign with the first value.
+     * @return {@code true} if the given values are not NaN and have the same sign.
+     *
+     * @see Math#signum(double)
+     */
+    public static boolean isSameSign(final double v1, final double v2) {
+        return !Double.isNaN(v1) && !Double.isNaN(v2) &&
+                ((doubleToRawLongBits(v1) ^ doubleToRawLongBits(v2)) & SIGN_BIT_MASK) == 0;
+    }
+
+    /**
+     * Returns the first floating-point argument with the sign reversed if the second floating-point
+     * argument is negative. This method is similar to <code>{@linkplain Math#copySign(double,double)
+     * Math.copySign}(value, sign)</code> except that the sign is combined with an <cite>exclusive
+     * or</cite> operation instead than being copied.
+     * <p>
+     * This method makes no guarantee about whether {@code NaN} values are handled as positive
+     * or negative numbers. This is the same policy than {@link Math#copySign(double, double)}.
+     *
+     * @param  value The parameter providing the value that may need a sign change.
+     * @param  sign The parameter providing the sign to <cite>xor</cite> with the value.
+     * @return The provided value with its sign reversed if the {@code sign} parameter is negative.
+     *
+     * @see Math#copySign(double, double)
+     */
+    public static double xorSign(final double value, final double sign) {
+        return longBitsToDouble(doubleToRawLongBits(value) ^
+                (doubleToRawLongBits(sign) & SIGN_BIT_MASK));
+    }
+
+    /**
+     * Returns the sign of <var>x</var>. This method returns
+     *    -1 if <var>x</var> is negative,
+     *     0 if <var>x</var> is zero or {@code NaN} and
+     *    +1 if <var>x</var> is positive.
+     *
+     * @param x The number from which to get the sign.
+     * @return {@code +1} if <var>x</var> is positive, {@code -1} if negative, or 0 otherwise.
+     *
+     * @see Math#signum(double)
+     */
+    public static int sgn(final double x) {
+        if (x > 0) return +1;
+        if (x < 0) return -1;
+        else       return  0;
+    }
+
+    /**
+     * Returns the sign of <var>x</var>. This method returns
+     *    -1 if <var>x</var> is negative,
+     *     0 if <var>x</var> is zero or {@code NaN} and
+     *    +1 if <var>x</var> is positive.
+     *
+     * @param x The number from which to get the sign.
+     * @return {@code +1} if <var>x</var> is positive, {@code -1} if negative, or 0 otherwise.
+     *
+     * @see Math#signum(float)
+     */
+    public static int sgn(final float x) {
+        if (x > 0) return +1;
+        if (x < 0) return -1;
+        else       return  0;
+    }
+
+    /**
+     * Returns the sign of <var>x</var>. This method returns
+     *    -1 if <var>x</var> is negative,
+     *     0 if <var>x</var> is zero and
+     *    +1 if <var>x</var> is positive.
+     *
+     * @param x The number from which to get the sign.
+     * @return {@code +1} if <var>x</var> is positive, {@code -1} if negative, or 0 otherwise.
+     */
+    public static int sgn(long x) {
+        if (x > 0) return +1;
+        if (x < 0) return -1;
+        else       return  0;
+    }
+
+    /**
+     * Returns the sign of <var>x</var>. This method returns
+     *    -1 if <var>x</var> is negative,
+     *     0 if <var>x</var> is zero and
+     *    +1 if <var>x</var> is positive.
+     *
+     * @param x The number from which to get the sign.
+     * @return {@code +1} if <var>x</var> is positive, {@code -1} if negative, or 0 otherwise.
+     */
+    public static int sgn(int x) {
+        if (x > 0) return +1;
+        if (x < 0) return -1;
+        else       return  0;
+    }
+
+    /**
+     * Returns the sign of <var>x</var>. This method returns
+     *    -1 if <var>x</var> is negative,
+     *     0 if <var>x</var> is zero and
+     *    +1 if <var>x</var> is positive.
+     *
+     * @param x The number from which to get the sign.
+     * @return {@code +1} if <var>x</var> is positive, {@code -1} if negative, or 0 otherwise.
+     */
+    public static short sgn(short x) {
+        if (x > 0) return (short) +1;
+        if (x < 0) return (short) -1;
+        else       return (short)  0;
+    }
+
+    /**
+     * Returns the sign of <var>x</var>. This method returns
+     *    -1 if <var>x</var> is negative,
+     *     0 if <var>x</var> is zero and
+     *    +1 if <var>x</var> is positive.
+     *
+     * @param x The number from which to get the sign.
+     * @return {@code +1} if <var>x</var> is positive, {@code -1} if negative, or 0 otherwise.
+     */
+    public static byte sgn(byte x) {
+        if (x > 0) return (byte) +1;
+        if (x < 0) return (byte) -1;
+        else       return (byte)  0;
+    }
+
+    /**
+     * Returns a {@linkplain Float#isNaN(float) NaN} number for the specified ordinal value.
+     * Valid NaN numbers in Java can have bit fields in the ranges listed below.
+     * This method allocate one of valid NaN bit fields to each ordinal value.
+     * <p>
+     * <ul>
+     *   <li>[{@code 0x7F800001} … {@code 0x7FFFFFFF}], with
+     *        {@code 0x7FC00000} as the bit fields of the standard {@link Float#NaN} value</li>
+     *   <li>[{@code 0xFF800001} … {@code 0xFFFFFFFF}]</li>
+     * </ul>
+     * <p>
+     * The relationship between bit fields and ordinal values is implementation dependent and may
+     * change in any future version of the SIS library. The current implementation restricts the
+     * range of allowed ordinal values to a smaller one than the range of all possible NaN values.
+     * However we
+     *
+     * @param  ordinal The NaN ordinal value, from {@code -0x200000} to {@code 0x1FFFFF} inclusive.
+     * @return One of the legal {@linkplain Float#isNaN(float) NaN} values as a float.
+     * @throws IllegalArgumentException if the specified ordinal is out of range.
+     *
+     * @see Float#intBitsToFloat(int)
+     */
+    public static float toNanFloat(final int ordinal) throws IllegalArgumentException {
+        ArgumentChecks.ensureBetween("ordinal", MIN_NAN_ORDINAL, MAX_NAN_ORDINAL, ordinal);
+        final float value = intBitsToFloat(0x7FC00000 + ordinal);
+        assert Float.isNaN(value) && toNanOrdinal(value) == ordinal : ordinal;
+        return value;
+    }
+
+    /**
+     * Returns the ordinal value of the given NaN number.
+     * This method is the converse of {@link #toNanFloat(int)}.
+     *
+     * @param  value The value from which to get the NaN ordinal value.
+     * @return The NaN ordinal value of the given floating point value.
+     * @throws IllegalArgumentException If the given value is not a NaN value,
+     *         or does not use a supported bits pattern.
+     */
+    public static int toNanOrdinal(final float value) throws IllegalArgumentException {
+        final int ordinal = floatToRawIntBits(value) - 0x7FC00000;
+        if (ordinal >= MIN_NAN_ORDINAL && ordinal <= MAX_NAN_ORDINAL) {
+            return ordinal;
+        }
+        final int resourceKey;
+        final Object obj;
+        if (Float.isNaN(value)) {
+            resourceKey = Errors.Keys.IllegalBitsPattern_1;
+            obj = Integer.toHexString(ordinal);
+        } else {
+            resourceKey = Errors.Keys.IllegalArgumentValue_2;
+            obj = value;
+        }
+        throw new IllegalArgumentException(Errors.format(resourceKey, obj));
+    }
+
+    /**
+     * Returns the <var>i</var><sup>th</sup> prime number.
+     * This method returns (2, 3, 5, 7, 11, …) for index (0, 1, 2, 3, 4, …).
+     *
+     * @param  index The prime number index, starting at index 0 for prime number 2.
+     * @return The prime number at the specified index.
+     * @throws IndexOutOfBoundsException if the specified index is too large.
+     *
+     * @see java.math.BigInteger#isProbablePrime(int)
+     */
+    static int primeNumberAt(final int index) throws IndexOutOfBoundsException {
+        ArgumentChecks.ensureValidIndex(PRIMES_LENGTH_16_BITS, index);
+        short[] primes = MathFunctions.primes;
+        if (index >= primes.length) {
+            synchronized (MathFunctions.class) {
+                primes = MathFunctions.primes;
+                if (index >= primes.length) {
+                    int i = primes.length;
+                    int n = primes[i - 1] & 0xFFFF;
+                    // Compute by block of 16 values, for reducing the amount of array resize.
+                    primes = Arrays.copyOf(primes, Math.min((index | 0xF) + 1, PRIMES_LENGTH_16_BITS));
+                    do {
+testNextNumber:         while (true) { // Simulate a "goto" statement (usually not recommanded...)
+                            final int stopAt = (int) Math.sqrt(n += 2);
+                            int prime;
+                            int j = 0;
+                            do {
+                                prime = primes[++j] & 0xFFFF;
+                                if (n % prime == 0) {
+                                    continue testNextNumber;
+                                }
+                            } while (prime <= stopAt);
+                            primes[i] = (short) n;
+                            break;
+                        }
+                    } while (++i < primes.length);
+                    MathFunctions.primes = primes;
+                }
+            }
+        }
+        return primes[index] & 0xFFFF;
+    }
+
+    /**
+     * Returns the first prime number equals or greater than the given value.
+     * Current implementation accepts only values in the
+     * [2 … {@value #HIGHEST_SUPPORTED_PRIME_NUMBER}] range.
+     *
+     * @param  number The number for which to find the next prime.
+     * @return The given number if it is a prime number, or the next prime number otherwise.
+     * @throws IllegalArgumentException If the given value is outside the supported range.
+     */
+    public static int nextPrimeNumber(final int number) throws IllegalArgumentException {
+        ArgumentChecks.ensureBetween("number", 2, HIGHEST_SUPPORTED_PRIME_NUMBER, number);
+        final short[] primes = MathFunctions.primes;
+        int lower = 0;
+        int upper = Math.min(PRIMES_LENGTH_15_BITS, primes.length);
+        if (number > Short.MAX_VALUE) {
+            lower = upper;
+            upper = primes.length;
+        }
+        int i = Arrays.binarySearch(primes, lower, upper, (short) number);
+        if (i < 0) {
+            i = ~i;
+            if (i >= primes.length) {
+                int p;
+                do p = primeNumberAt(i++);
+                while (p < number);
+                return p;
+            }
+        }
+        return primes[i] & 0xFFFF;
+    }
+
+    /**
+     * Returns the divisors of the specified number as positive integers. For any value other
+     * than {@code O} (which returns an empty array), the first element in the returned array
+     * is always {@code 1} and the last element is always the absolute value of {@code number}.
+     *
+     * @param number The number for which to compute the divisors.
+     * @return The divisors in strictly increasing order.
+     */
+    public static int[] divisors(int number) {
+        if (number == 0) {
+            return EMPTY_INT;
+        }
+        number = Math.abs(number);
+        int[] divisors = new int[16];
+        divisors[0] = 1;
+        int count = 1;
+        /*
+         * Searches for the first divisors among the prime numbers. We stop the search at the
+         * square root of 'n' because every values above that point can be inferred from the
+         * values before that point, i.e. if n=p1*p2 and p2 is greater than 'sqrt', than p1
+         * most be lower than 'sqrt'.
+         */
+        final int sqrt = (int) Math.sqrt(number); // Really wants rounding toward 0.
+        for (int p,i=0; (p=primeNumberAt(i)) <= sqrt; i++) {
+            if (number % p == 0) {
+                if (count == divisors.length) {
+                    divisors = Arrays.copyOf(divisors, count*2);
+                }
+                divisors[count++] = p;
+            }
+        }
+        /*
+         * Completes the divisors past 'sqrt'. The numbers added here may or may not be prime
+         * numbers. Side note: checking that they are prime numbers would be costly, but this
+         * algorithm doesn't need that.
+         */
+        int source = count;
+        if (count*2 > divisors.length) {
+            divisors = Arrays.copyOf(divisors, count*2);
+        }
+        int d1 = divisors[--source];
+        int d2 = number / d1;
+        if (d1 != d2) {
+            divisors[count++] = d2;
+        }
+        while (--source >= 0) {
+            divisors[count++] = number / divisors[source];
+        }
+        /*
+         * Checks the products of divisors found so far. For example if 2 and 3 are divisors,
+         * checks if 6 is a divisor as well. The products found will themself be used for
+         * computing new products.
+         */
+        for (int i=1; i<count; i++) {
+            d1 = divisors[i];
+            for (int j=i; j<count; j++) {
+                d2 = d1 * divisors[j];
+                if (number % d2 == 0) {
+                    int p = Arrays.binarySearch(divisors, j, count, d2);
+                    if (p < 0) {
+                        p = ~p; // ~ operator, not minus
+                        if (count == divisors.length) {
+                            divisors = Arrays.copyOf(divisors, count*2);
+                        }
+                        System.arraycopy(divisors, p, divisors, p+1, count-p);
+                        divisors[p] = d2;
+                        count++;
+                    }
+                }
+            }
+        }
+        divisors = resize(divisors, count);
+        assert isSorted(divisors, true);
+        return divisors;
+    }
+
+    /**
+     * Returns the divisors which are common to all the specified numbers.
+     *
+     * @param  numbers The numbers for which to compute the divisors.
+     * @return The divisors common to all the given numbers, in strictly increasing order.
+     */
+    public static int[] commonDivisors(final int... numbers) {
+        if (numbers.length == 0) {
+            return EMPTY_INT;
+        }
+        /*
+         * Get the smallest value. We will compute the divisors only for this value,
+         * since we know that any value greater that the minimal value can not be a
+         * common divisor.
+         */
+        int minValue = Integer.MAX_VALUE;
+        for (int i=0; i<numbers.length; i++) {
+            final int n = Math.abs(numbers[i]);
+            if (n <= minValue) {
+                minValue = n;
+            }
+        }
+        int[] divisors = divisors(minValue);
+        /*
+         * Tests if the divisors we just found are also divisors of all other numbers.
+         * Removes those which are not.
+         */
+        int count = divisors.length;
+        for (int i=0; i<numbers.length; i++) {
+            final int n = Math.abs(numbers[i]);
+            if (n != minValue) {
+                for (int j=count; --j>0;) { // Do not test j==0, since divisors[0] ==  1.
+                    if (n % divisors[j] != 0) {
+                        System.arraycopy(divisors, j+1, divisors, j, --count - j);
+                    }
+                }
+            }
+        }
+        return resize(divisors, count);
+    }
+}

Propchange: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java?rev=1394562&view=auto
==============================================================================
--- sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java (added)
+++ sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java Fri Oct  5 15:02:23 2012
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A set of mathematical objects and algebraic utilities.
+ *
+ * {@section References:}
+ * <ul>
+ *   <li><a href="http://mathworld.wolfram.com/">Eric Weisstein's World of Mathematic</a></li>
+ *   <li><a href="http://www.worldserver.com/turk/opensource/">Ken Turkiwski's Open Source Repository</a></li>
+ * </ul>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.0)
+ * @version 0.3
+ * @module
+ */
+package org.apache.sis.math;

Propchange: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/math/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1394562&r1=1394561&r2=1394562&view=diff
==============================================================================
--- sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java (original)
+++ sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java Fri Oct  5 15:02:23 2012
@@ -57,6 +57,21 @@ public final class Errors extends Indexe
         public static final int IllegalArgumentClass_3 = 2;
 
         /**
+         * Argument ‘{0}’ can not take the “{1}” value.
+         */
+        public static final int IllegalArgumentValue_2 = 14;
+
+        /**
+         * Illegal value for argument ‘{0}’.
+         */
+        public static final int IllegalArgument_1 = 15;
+
+        /**
+         * Illegal bits pattern: {0}.
+         */
+        public static final int IllegalBitsPattern_1 = 16;
+
+        /**
          * Class ‘{0}’ is illegal. It must be ‘{1}’ or a derived class.
          */
         public static final int IllegalClass_2 = 3;

Modified: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1394562&r1=1394561&r2=1394562&view=diff
==============================================================================
--- sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties (original)
+++ sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties Fri Oct  5 15:02:23 2012
@@ -14,17 +14,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-EmptyArgument_1=Argument \u2018{0}\u2019 shall not be empty.
-IllegalArgumentClass_3=Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019. Expected an instance of \u2018{2}\u2019 or derived type.
-IllegalClass_2=Class \u2018{0}\u2019 is illegal. It must be \u2018{1}\u2019 or a derived class.
-IllegalLanguageCode_1=The \u201c{0}\u201d language is not recognized.
-IllegalRange_2=Range [{0} \u2026 {1}] is not valid.
-IndexOutOfBounds_1=Index {0} is out of bounds.
-NegativeArgument_2=Argument \u2018{0}\u2019 shall not be negative. The given value was {1}.
-NotANumber_1=Argument \u2018{0}\u2019 shall not be NaN (Not-a-Number).
-NotAPrimitiveWrapper_1=Class \u2018{0}\u2019 is not a primitive type wrapper.
-NullArgument_1=Argument \u2018{0}\u2019 shall not be null.
-UnexpectedArgumentDimension_3=Argument \u2018{0}\u2019 has {1} dimensions, while {2} was expected.
-ValueAlreadyDefined_1=A value is already defined for \u201c{0}\u201d.
-ValueNotGreaterThanZero_2=Value \u2018{0}\u2019={1} is invalid. Expected a number greater than 0.
-ValueOutOfRange_4=Value \u2018{0}\u2019={1} is invalid. Expected a value in the [{2} \u2026 {3}] range.
+EmptyArgument_1                 = Argument \u2018{0}\u2019 shall not be empty.
+IllegalArgument_1               = Illegal value for argument \u2018{0}\u2019.
+IllegalArgumentClass_3          = Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019. Expected an instance of \u2018{2}\u2019 or derived type.
+IllegalArgumentValue_2          = Argument \u2018{0}\u2019 can not take the \u201c{1}\u201d value.
+IllegalBitsPattern_1            = Illegal bits pattern: {0}.
+IllegalClass_2                  = Class \u2018{0}\u2019 is illegal. It must be \u2018{1}\u2019 or a derived class.
+IllegalLanguageCode_1           = The \u201c{0}\u201d language is not recognized.
+IllegalRange_2                  = Range [{0} \u2026 {1}] is not valid.
+IndexOutOfBounds_1              = Index {0} is out of bounds.
+NegativeArgument_2              = Argument \u2018{0}\u2019 shall not be negative. The given value was {1}.
+NotANumber_1                    = Argument \u2018{0}\u2019 shall not be NaN (Not-a-Number).
+NotAPrimitiveWrapper_1          = Class \u2018{0}\u2019 is not a primitive type wrapper.
+NullArgument_1                  = Argument \u2018{0}\u2019 shall not be null.
+UnexpectedArgumentDimension_3   = Argument \u2018{0}\u2019 has {1} dimensions, while {2} was expected.
+ValueAlreadyDefined_1           = A value is already defined for \u201c{0}\u201d.
+ValueNotGreaterThanZero_2       = Value \u2018{0}\u2019={1} is invalid. Expected a number greater than 0.
+ValueOutOfRange_4               = Value \u2018{0}\u2019={1} is invalid. Expected a value in the [{2} \u2026 {3}] range.

Modified: sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1394562&r1=1394561&r2=1394562&view=diff
==============================================================================
--- sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties (original)
+++ sis/branches/JDK6/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties Fri Oct  5 15:02:23 2012
@@ -14,17 +14,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-EmptyArgument_1=L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre vide.
-IllegalArgumentClass_3=L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019. Une instance de \u2018{2}\u2019 ou d\u2019un type d\u00e9riv\u00e9 \u00e9tait attendue.
-IllegalClass_2=La classe \u2018{0}\u2019 est ill\u00e9gale. Il doit s\u2019agir d\u2019une classe \u2018{1}\u2019 ou d\u00e9riv\u00e9e.
-IllegalLanguageCode_1=Le code de langue \u201c{0}\u201d n\u2019est pas reconnu.
-IllegalRange_2=La plage [{0} \u2026 {1}] n\u2019est pas valide.
-IndexOutOfBounds_1=L\u2019index {0} est en dehors des limites permises.
-NegativeArgument_2=L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre n\u00e9gatif. La valeur donn\u00e9e \u00e9tait {1}.
-NotANumber_1=L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre NaN (Not-a-Number).
-NotAPrimitiveWrapper_1=La classe \u2018{0}\u2019 n\u2019est pas un adaptateur d\u2019un type primitif.
-NullArgument_1=L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre nul.
-UnexpectedArgumentDimension_3=L\u2019argument \u2018{0}\u2019 a {1} dimensions, alors qu\u2019on en attendait {2}.
-ValueAlreadyDefined_1=Une valeur est d\u00e9j\u00e0 d\u00e9finie pour \u201c{0}\u201d.
-ValueNotGreaterThanZero_2=La valeur \u2018{0}\u2019={1} n\u2019est pas valide. On attendait un nombre positif non-nul.
-ValueOutOfRange_4=La valeur \u2018{0}\u2019={1} est invalide. Une valeur dans la plage [{2} \u2026 {3}] \u00e9tait attendue.
+EmptyArgument_1                 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre vide.
+IllegalArgument_1               = Valeur ill\u00e9gale pour l\u2019argument \u2018{0}\u2019.
+IllegalArgumentClass_3          = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019. Une instance de \u2018{2}\u2019 ou d\u2019un type d\u00e9riv\u00e9 \u00e9tait attendue.
+IllegalArgumentValue_2          = L\u2019argument \u2018{0}\u2019 n\u2019accepte pas la valeur \u201c{1}\u201d.
+IllegalBitsPattern_1            = Pattern de bits invalide: {0}.
+IllegalClass_2                  = La classe \u2018{0}\u2019 est ill\u00e9gale. Il doit s\u2019agir d\u2019une classe \u2018{1}\u2019 ou d\u00e9riv\u00e9e.
+IllegalLanguageCode_1           = Le code de langue \u201c{0}\u201d n\u2019est pas reconnu.
+IllegalRange_2                  = La plage [{0} \u2026 {1}] n\u2019est pas valide.
+IndexOutOfBounds_1              = L\u2019index {0} est en dehors des limites permises.
+NegativeArgument_2              = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre n\u00e9gatif. La valeur donn\u00e9e \u00e9tait {1}.
+NotANumber_1                    = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre NaN (Not-a-Number).
+NotAPrimitiveWrapper_1          = La classe \u2018{0}\u2019 n\u2019est pas un adaptateur d\u2019un type primitif.
+NullArgument_1                  = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre nul.
+UnexpectedArgumentDimension_3   = L\u2019argument \u2018{0}\u2019 a {1} dimensions, alors qu\u2019on en attendait {2}.
+ValueAlreadyDefined_1           = Une valeur est d\u00e9j\u00e0 d\u00e9finie pour \u201c{0}\u201d.
+ValueNotGreaterThanZero_2       = La valeur \u2018{0}\u2019={1} n\u2019est pas valide. On attendait un nombre positif non-nul.
+ValueOutOfRange_4               = La valeur \u2018{0}\u2019={1} est invalide. Une valeur dans la plage [{2} \u2026 {3}] \u00e9tait attendue.

Added: sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java?rev=1394562&view=auto
==============================================================================
--- sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java (added)
+++ sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java Fri Oct  5 15:02:23 2012
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.math;
+
+import org.junit.Test;
+import org.apache.sis.test.TestCase;
+import org.apache.sis.test.DependsOnMethod;
+
+import static org.junit.Assert.*;
+import static org.apache.sis.math.MathFunctions.*;
+import static org.apache.sis.util.Arrays.isSorted;
+
+
+/**
+ * Tests the {@link MathFunctions} static methods.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ */
+public final strictfp class MathFunctionsTest extends TestCase {
+    /**
+     * Small number for floating point comparisons.
+     */
+    private static final double EPS = 1E-12;
+
+    /**
+     * Highest prime number representable as a signed {@code short}.
+     */
+    private static final int HIGHEST_SHORT_PRIME = 32749;
+
+    /**
+     * The lowest prime number for which unsigned {@code short} is necessary.
+     */
+    private static final int LOWEST_USHORT_PRIME = 32771;
+
+    /**
+     * Tests the {@link MathFunctions#magnitude(double[])} method.
+     */
+    @Test
+    public void testMagnitude() {
+        assertEquals(0, magnitude(), EPS);
+        assertEquals(4, magnitude(0, -4, 0), EPS);
+        assertEquals(5, magnitude(0, -4, 0, 3, 0), EPS);
+        assertEquals(5, magnitude(3, 1, -2, 1, -3, -1), EPS);
+    }
+
+    /**
+     * Tests the {@link MathFunctions#pow10(double)} method.
+     * This will indirectly test {@link MathFunctions#pow10(int)}
+     * since the former will delegate to the later in this test.
+     */
+    @Test
+    public void testPow10() {
+        for (int i=-304; i<=304; i++) { // Range of allowed exponents in base 10.
+            assertEquals(Double.parseDouble("1E"+i), pow10((double) i), 0);
+        }
+    }
+
+    /**
+     * Tests the {@link MathFunctions#atanh(double)} method in the [-1 … +1] range.
+     */
+    @Test
+    public void testAtanh() {
+        for (int i=-10; i<=10; i++) {
+            final double x = 0.1 * i;
+            final double y = atanh(x);
+            switch (i) {
+                case -10: assertEquals(Double.NEGATIVE_INFINITY, y, EPS); break;
+                default:  assertEquals(x, Math.tanh(y),             EPS); break;
+                case +10: assertEquals(Double.POSITIVE_INFINITY, y, EPS); break;
+            }
+        }
+    }
+
+    /**
+     * Tests the {@link MathFunctions#xorSign(double, double)} method.
+     */
+    @Test
+    public void testXorSign() {
+        assertEquals( 10, xorSign( 10,  0.5), 0);
+        assertEquals(-10, xorSign(-10,  0.5), 0);
+        assertEquals( 10, xorSign(-10, -0.5), 0);
+        assertEquals(-10, xorSign( 10, -0.5), 0);
+    }
+
+    /**
+     * Tests the {@link MathFunctions#toNanFloat(int)} method. This will indirectly test the
+     * converse {@link MathFunctions#toNanOrdinal(float)} method through Java assertions.
+     */
+    public void testToNanFloat() {
+        final int standardNaN = Float.floatToRawIntBits(Float.NaN);
+        for (int ordinal = 0; ordinal < MathFunctions.MAX_NAN_ORDINAL; ordinal += 256) {
+            final float vp = toNanFloat(+ordinal);
+            final float vn = toNanFloat(-ordinal);
+            final int   bp = Float.floatToRawIntBits(vp);
+            final int   bn = Float.floatToRawIntBits(vn);
+            assertEquals(ordinal == 0, standardNaN == bp);
+            assertEquals(ordinal == 0, standardNaN == bn);
+            assertEquals(ordinal == 0, bp == bn);
+        }
+    }
+
+    /**
+     * Tests the {@link MathFunctions#primeNumberAt(int)} method.
+     */
+    @Test
+    public void testPrimeNumberAt() {
+        final int[] primes = {
+              2,   3,   5,   7,  11,  13,  17,  19,  23,  29,  31,  37,  41,  43,  47,  53 , 59,
+             61,  67,  71,  73,  79,  83,  89,  97, 101, 103, 107, 109, 113, 127, 131, 137, 139,
+            149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
+            239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337,
+            347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
+            443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557,
+            563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653,
+            659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
+            773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883,
+            887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
+        };
+        for (int i=0; i<primes.length; i++) {
+            assertEquals(primes[i], primeNumberAt(i));
+        }
+        assertEquals(HIGHEST_SHORT_PRIME,            primeNumberAt(PRIMES_LENGTH_15_BITS - 1));
+        assertEquals(HIGHEST_SUPPORTED_PRIME_NUMBER, primeNumberAt(PRIMES_LENGTH_16_BITS - 1));
+    }
+
+    /**
+     * Tests the {@link MathFunctions#nextPrimeNumber(int)} method.
+     */
+    @Test
+    @DependsOnMethod("testPrimeNumberAt")
+    public void testNextPrimeNumber() {
+        assertEquals(151, nextPrimeNumber(151));
+        assertEquals(157, nextPrimeNumber(152));
+        assertEquals(997, nextPrimeNumber(996));
+        assertEquals(HIGHEST_SHORT_PRIME,            nextPrimeNumber(HIGHEST_SHORT_PRIME - 1));
+        assertEquals(HIGHEST_SHORT_PRIME,            nextPrimeNumber(HIGHEST_SHORT_PRIME));
+        assertEquals(LOWEST_USHORT_PRIME,            nextPrimeNumber(HIGHEST_SHORT_PRIME + 1));
+        assertEquals(32779,                          nextPrimeNumber(LOWEST_USHORT_PRIME + 1));
+        assertEquals(HIGHEST_SUPPORTED_PRIME_NUMBER, nextPrimeNumber(HIGHEST_SUPPORTED_PRIME_NUMBER - 1));
+        assertEquals(HIGHEST_SUPPORTED_PRIME_NUMBER, nextPrimeNumber(HIGHEST_SUPPORTED_PRIME_NUMBER));
+    }
+
+    /**
+     * Tests the {@link MathFunctions#divisors(int)} method.
+     */
+    @Test
+    @DependsOnMethod("testPrimeNumberAt")
+    public void testDivisors() {
+        for (int i=0; i<10000; i++) {
+            final int[] divisors = divisors(i);
+            assertTrue(isSorted(divisors, true));
+            for (int j=0; j<divisors.length; j++) {
+                assertEquals(0, i % divisors[j]);
+            }
+            if (i == 0){
+                assertEquals(0, divisors.length);
+            } else {
+                assertEquals(1, divisors[0]);
+                assertEquals(i, divisors[divisors.length - 1]);
+            }
+        }
+        assertArrayEquals(new int[] {
+            1, 2, 4, 5, 8, 10, 16, 20, 25, 40, 50, 80, 100, 125, 200, 250, 400, 500, 1000, 2000
+        }, divisors(2000));
+
+        assertArrayEquals(new int[] {
+            1, 61, 71, 4331
+        }, divisors(4331));
+
+        assertArrayEquals(new int[] {
+            1, 2, 3, 4, 5, 6, 8, 10, 12, 13, 15, 20, 24, 25, 26, 30, 39, 40, 50, 52, 60, 65, 75,
+            78, 100, 104, 120, 130, 150, 156, 195, 200, 260, 300, 312, 325, 390, 520, 600, 650,
+            780, 975, 1300, 1560, 1950, 2600, 3900, 7800
+        }, divisors(7800));
+    }
+
+    /**
+     * Tests the {@link MathFunctions#commonDivisors(int[])} method.
+     */
+    @Test
+    @DependsOnMethod("testDivisors")
+    public void testCommonDivisors() {
+        assertArrayEquals(new int[] {
+            1, 5
+        }, commonDivisors(2000, 15));
+    }
+}

Propchange: sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1394562&r1=1394561&r2=1394562&view=diff
==============================================================================
--- sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java (original)
+++ sis/branches/JDK6/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java Fri Oct  5 15:02:23 2012
@@ -46,7 +46,8 @@ import org.junit.runners.Suite;
   org.apache.sis.util.type.DefaultInternationalStringTest.class,
   org.apache.sis.internal.util.ReferenceQueueConsumerTest.class,
   org.apache.sis.util.collection.WeakHashSetTest.class,
-  org.apache.sis.util.collection.WeakValueHashMapTest.class
+  org.apache.sis.util.collection.WeakValueHashMapTest.class,
+  org.apache.sis.math.MathFunctionsTest.class
 })
 public final strictfp class UtilityTestSuite extends TestSuite {
 }



Mime
View raw message