MathFunc.java Source code

Java tutorial

Introduction

Here is the source code for MathFunc.java

Source

//package org.j4me.util;

/**
 * Implements the methods which are in the standard J2SE's <code>Math</code> class,
 * but are not in in J2ME's.
 * <p>
 * The following methods are still missing from the implementation:
 * <ul>
 *  <li><code>public static double exp (double a)</code>
 *  <li><code>public static double log (double a)</code>
 *  <li><code>public static double pow (double a, double b)</code>
 *  <li><code>public static double random ()</code>
 *  <li><code>public static double rint()</code>
 * </ul>
 * 
 * @see java.lang.Math
 */
public final class MathFunc {
    /**
     * Constant for PI divided by 2.
     */
    private static final double PIover2 = Math.PI / 2;

    /**
     * Constant for PI divided by 4.
     */
    private static final double PIover4 = Math.PI / 4;

    /**
     * Constant for PI divided by 6.
     */
    private static final double PIover6 = Math.PI / 6;

    /**
     * Constant for PI divided by 12.
     */
    private static final double PIover12 = Math.PI / 12;

    /**
     * Constant used in the <code>atan</code> calculation.
     */
    private static final double ATAN_CONSTANT = 1.732050807569;

    /**
     * Returns the arc cosine of an angle, in the range of 0.0 through <code>Math.PI</code>.
     * Special case:
     * <ul>
     *  <li>If the argument is <code>NaN</code> or its absolute value is greater than 1,
     *      then the result is <code>NaN</code>.
     * </ul>
     * 
     * @param a - the value whose arc cosine is to be returned.
     * @return the arc cosine of the argument.
     */
    public static double acos(double a) {
        // Special case.
        if (Double.isNaN(a) || Math.abs(a) > 1.0) {
            return Double.NaN;
        }

        // Calculate the arc cosine.
        double aSquared = a * a;
        double arcCosine = atan2(Math.sqrt(1 - aSquared), a);
        return arcCosine;
    }

    /**
     * Returns the arc sine of an angle, in the range of <code>-Math.PI/2</code> through
     * <code>Math.PI/2</code>.  Special cases:
     * <ul>
     *  <li>If the argument is <code>NaN</code> or its absolute value is greater than 1,
     *      then the result is <code>NaN</code>.
     *  <li>If the argument is zero, then the result is a zero with the same sign
     *      as the argument.
     * </ul>
     * 
     * @param a - the value whose arc sine is to be returned.
     * @return the arc sine of the argument.
     */
    public static double asin(double a) {
        // Special cases.
        if (Double.isNaN(a) || Math.abs(a) > 1.0) {
            return Double.NaN;
        }

        if (a == 0.0) {
            return a;
        }

        // Calculate the arc sine.
        double aSquared = a * a;
        double arcSine = atan2(a, Math.sqrt(1 - aSquared));
        return arcSine;
    }

    /**
     * Returns the arc tangent of an angle, in the range of <code>-Math.PI/2</code>
     * through <code>Math.PI/2</code>.  Special cases:
     * <ul>
     *  <li>If the argument is <code>NaN</code>, then the result is <code>NaN</code>.
     *  <li>If the argument is zero, then the result is a zero with the same 
     *      sign as the argument.
     * </ul>
     * <p>
     * A result must be within 1 ulp of the correctly rounded result.  Results
     * must be semi-monotonic.
     * 
     * @param a - the value whose arc tangent is to be returned. 
     * @return the arc tangent of the argument.
     */
    public static double atan(double a) {
        // Special cases.
        if (Double.isNaN(a)) {
            return Double.NaN;
        }

        if (a == 0.0) {
            return a;
        }

        // Compute the arc tangent.
        boolean negative = false;
        boolean greaterThanOne = false;
        int i = 0;

        if (a < 0.0) {
            a = -a;
            negative = true;
        }

        if (a > 1.0) {
            a = 1.0 / a;
            greaterThanOne = true;
        }

        double t;

        for (; a > PIover12; a *= t) {
            i++;
            t = a + ATAN_CONSTANT;
            t = 1.0 / t;
            a *= ATAN_CONSTANT;
            a--;
        }

        double aSquared = a * a;

        double arcTangent = aSquared + 1.4087812;
        arcTangent = 0.55913709 / arcTangent;
        arcTangent += 0.60310578999999997;
        arcTangent -= 0.051604539999999997 * aSquared;
        arcTangent *= a;

        for (; i > 0; i--) {
            arcTangent += PIover6;
        }

        if (greaterThanOne) {
            arcTangent = PIover2 - arcTangent;
        }

        if (negative) {
            arcTangent = -arcTangent;
        }

        return arcTangent;
    }

    /**
     * Converts rectangular coordinates (x, y) to polar (r, <i>theta</i>).  This method
     * computes the phase <i>theta</i> by computing an arc tangent of y/x in the range
     * of <i>-pi</i> to <i>pi</i>.  Special cases:
     * <ul>
     *  <li>If either argument is <code>NaN</code>, then the result is <code>NaN</code>.
     *  <li>If the first argument is positive zero and the second argument is
     *      positive, or the first argument is positive and finite and the second
     *      argument is positive infinity, then the result is positive zero.
     *  <li>If the first argument is negative zero and the second argument is
     *      positive, or the first argument is negative and finite and the second
     *      argument is positive infinity, then the result is negative zero.
     *  <li>If the first argument is positive zero and the second argument is 
     *      negative, or the first argument is positive and finite and the second
     *      argument is negative infinity, then the result is the <code>double</code> value 
     *      closest to <i>pi</i>.
     *  <li>If the first argument is negative zero and the second argument is 
     *      negative, or the first argument is negative and finite and the second
     *      argument is negative infinity, then the result is the <code>double</code> value
     *      closest to <i>-pi</i>.
     *  <li>If the first argument is positive and the second argument is positive
     *      zero or negative zero, or the first argument is positive infinity and
     *      the second argument is finite, then the result is the <code>double</code> value 
     *      closest to <i>pi</i>/2.
     *  <li>If the first argument is negative and the second argument is positive
     *      zero or negative zero, or the first argument is negative infinity and
     *      the second argument is finite, then the result is the <code>double</code> value
     *      closest to <i>-pi</i>/2.
     *  <li>If both arguments are positive infinity, then the result is the double
     *      value closest to <i>pi</i>/4.
     *  <li>If the first argument is positive infinity and the second argument is
     *      negative infinity, then the result is the double value closest to 3*<i>pi</i>/4.
     *  <li>If the first argument is negative infinity and the second argument is
     *      positive infinity, then the result is the double value closest to -<i>pi</i>/4.
     *  <li>If both arguments are negative infinity, then the result is the double
     *      value closest to -3*<i>pi</i>/4.
     * </ul>
     * <p>
     * A result must be within 2 ulps of the correctly rounded result.  Results
     * must be semi-monotonic.
     * 
     * @param y - the ordinate coordinate
     * @param x - the abscissa coordinate 
     * @return the <i>theta</i> component of the point (r, <i>theta</i>) in polar
     *   coordinates that corresponds to the point (x, y) in Cartesian coordinates.
     */
    public static double atan2(double y, double x) {
        // Special cases.
        if (Double.isNaN(y) || Double.isNaN(x)) {
            return Double.NaN;
        } else if (Double.isInfinite(y)) {
            if (y > 0.0) // Positive infinity
            {
                if (Double.isInfinite(x)) {
                    if (x > 0.0) {
                        return PIover4;
                    } else {
                        return 3.0 * PIover4;
                    }
                } else if (x != 0.0) {
                    return PIover2;
                }
            } else // Negative infinity
            {
                if (Double.isInfinite(x)) {
                    if (x > 0.0) {
                        return -PIover4;
                    } else {
                        return -3.0 * PIover4;
                    }
                } else if (x != 0.0) {
                    return -PIover2;
                }
            }
        } else if (y == 0.0) {
            if (x > 0.0) {
                return y;
            } else if (x < 0.0) {
                return Math.PI;
            }
        } else if (Double.isInfinite(x)) {
            if (x > 0.0) // Positive infinity
            {
                if (y > 0.0) {
                    return 0.0;
                } else if (y < 0.0) {
                    return -0.0;
                }
            } else // Negative infinity
            {
                if (y > 0.0) {
                    return Math.PI;
                } else if (y < 0.0) {
                    return -Math.PI;
                }
            }
        } else if (x == 0.0) {
            if (y > 0.0) {
                return PIover2;
            } else if (y < 0.0) {
                return -PIover2;
            }
        }

        // Implementation a simple version ported from a PASCAL implementation:
        //   http://everything2.com/index.pl?node_id=1008481

        double arcTangent;

        // Use arctan() avoiding division by zero.
        if (Math.abs(x) > Math.abs(y)) {
            arcTangent = atan(y / x);
        } else {
            arcTangent = atan(x / y); // -PI/4 <= a <= PI/4

            if (arcTangent < 0) {
                arcTangent = -PIover2 - arcTangent; // a is negative, so we're adding
            } else {
                arcTangent = PIover2 - arcTangent;
            }
        }

        // Adjust result to be from [-PI, PI]
        if (x < 0) {
            if (y < 0) {
                arcTangent = arcTangent - Math.PI;
            } else {
                arcTangent = arcTangent + Math.PI;
            }
        }

        return arcTangent;
    }

    /**
     * Returns the closest <code>int</code> to the argument. The 
     * result is rounded to an integer by adding 1/2, taking the 
     * floor of the result, and casting the result to type <code>int</code>. 
     * In other words, the result is equal to the value of the expression:
     * <p>
     * <pre>(int)Math.floor(a + 0.5f)</pre>
     * <p>
     * Special cases:
     * <ul>
     *  <li>If the argument is NaN, the result is 0.
     *  <li>If the argument is negative infinity or any value less than or 
     *      equal to the value of <code>Integer.MIN_VALUE</code>, the result is 
     *      equal to the value of <code>Integer.MIN_VALUE</code>. 
     *  <li>If the argument is positive infinity or any value greater than or 
     *      equal to the value of <code>Integer.MAX_VALUE</code>, the result is 
     *      equal to the value of <code>Integer.MAX_VALUE</code>.
     * </ul> 
     *
     * @param  a - a floating-point value to be rounded to an integer.
     * @return the value of the argument rounded to the nearest <code>int</code> value.
     */
    public static int round(float a) {
        return (int) Math.floor(a + 0.5f);
    }

    /**
     * Returns the closest <code>long</code> to the argument. The result 
     * is rounded to an integer by adding 1/2, taking the floor of the 
     * result, and casting the result to type <code>long</code>. In other 
     * words, the result is equal to the value of the expression:
     * <p>
     * <pre>(long)Math.floor(a + 0.5d)</pre>
     * <p>
     * Special cases:
     * <ul>
     *  <li>If the argument is NaN, the result is 0.
     *  <li>If the argument is negative infinity or any value less than or 
     *      equal to the value of <code>Long.MIN_VALUE</code>, the result is 
     *      equal to the value of <code>Long.MIN_VALUE</code>. 
     *  <li>If the argument is positive infinity or any value greater than or 
     *      equal to the value of <code>Long.MAX_VALUE</code>, the result is 
     *      equal to the value of <code>Long.MAX_VALUE</code>.
     * </ul> 
     *
     * @param a - a floating-point value to be rounded to a <code>long</code>.
     * @return the value of the argument rounded to the nearest <code>long</code> value.
     */
    public static long round(double a) {
        return (long) Math.floor(a + 0.5);
    }
}