/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2001-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.resources;
import java.text.ChoiceFormat;
import org.geotools.resources.i18n.Errors;
import org.geotools.resources.i18n.ErrorKeys;
/**
* Simple mathematical functions.
*
* @since 2.0
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*/
public final class XMath {
/**
* Natural logarithm of 10.
* Approximately equal to 2.302585.
*
* @deprecated Was for {@link #log10} internal usage only.
*/
public static final double LN10 = 2.3025850929940456840179914546844;
/**
* Table of some integer powers of 10. Used
* for fast computation of {@link #pow10(int)}.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
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 allow instantiation of this class.
*/
private XMath() {
}
/**
* Computes the hypotenuse (<code>sqrt(x²+y²)</code>).
*
* @deprecated Replaced by {@link Math#hypot}.
*/
@Deprecated
public static double hypot(final double x, final double y) {
return Math.sqrt(x*x + y*y);
}
/**
* Computes the logarithm in base 10. See
* http://developer.java.sun.com/developer/bugParade/bugs/4074599.html.
*
* @deprecated Replaced by {@link Math#log10}.
*/
@Deprecated
public static double log10(final double x) {
return Math.log(x) / LN10;
}
/**
* Computes 10 power <var>x</var>.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static double pow10(final double x) {
return org.geotools.math.XMath.pow10(x);
}
/**
* Computes <var>x</var> to the power of 10. This computation is very fast
* for small power of 10 but has some rounding error issues (see
* http://developer.java.sun.com/developer/bugParade/bugs/4358794.html).
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static strictfp double pow10(final int x) {
return org.geotools.math.XMath.pow10(x);
}
/**
* Returns the sign of <var>x</var>. This method returns
* -1 if <var>x</var> is negative,
* 0 if <var>x</var> is null or {@code NaN} and
* +1 if <var>x</var> is positive.
*
* @see Math#signum(double)
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static int sgn(final double x) {
return org.geotools.math.XMath.sgn(x);
}
/**
* Returns the sign of <var>x</var>. This method returns
* -1 if <var>x</var> is negative,
* 0 if <var>x</var> is null or {@code NaN} and
* +1 if <var>x</var> is positive.
*
* @see Math#signum(float)
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static int sgn(final float x) {
return org.geotools.math.XMath.sgn(x);
}
/**
* Returns the sign of <var>x</var>. This method returns
* -1 if <var>x</var> is negative,
* 0 if <var>x</var> is null and
* +1 if <var>x</var> is positive.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static int sgn(long x) {
return org.geotools.math.XMath.sgn(x);
}
/**
* Returns the sign of <var>x</var>. This method returns
* -1 if <var>x</var> is negative,
* 0 if <var>x</var> is null and
* +1 if <var>x</var> is positive.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static int sgn(int x) {
return org.geotools.math.XMath.sgn(x);
}
/**
* Returns the sign of <var>x</var>. This method returns
* -1 if <var>x</var> is negative,
* 0 if <var>x</var> is null and
* +1 if <var>x</var> is positive.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static short sgn(short x) {
return org.geotools.math.XMath.sgn(x);
}
/**
* Returns the sign of <var>x</var>. This method returns
* -1 if <var>x</var> is negative,
* 0 if <var>x</var> is null and
* +1 if <var>x</var> is positive.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static byte sgn(byte x) {
return org.geotools.math.XMath.sgn(x);
}
/**
* Rounds the specified value, providing that the difference between the original value and
* the rounded value is not greater than the specified amount of floating point units. This
* method can be used for hiding floating point error likes 2.9999999996.
*
* @param value The value to round.
* @param flu The amount of floating point units.
* @return The rounded value, of {@code value} if it was not close enough to an integer.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static double round(final double value, int flu) {
return org.geotools.math.XMath.roundIfAlmostInteger(value, flu);
}
/**
* Tries to remove at least {@code n} fraction digits in the string representation of
* the specified value. This method try small changes to {@code value}, by adding or
* substracting a maximum of 4 ulps. If there is no small change that remove at least
* {@code n} fraction digits, then the value is returned unchanged. This method is
* used for hiding rounding errors, like in conversions from radians to degrees.
*
* <P>Example: {@code XMath.fixRoundingError(-61.500000000000014, 12)} returns
* {@code -61.5}.
*
* @param value The value to fix.
* @param n The minimum amount of fraction digits.
* @return The fixed value, or the unchanged {@code value} if there is no small change
* that remove at least {@code n} fraction digits.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static double fixRoundingError(final double value, int n) {
return org.geotools.math.XMath.trimDecimalFractionDigits(value, 4, n);
}
/**
* Counts the fraction digits in the string representation of
* the specified value. This method is equivalent to a call to
* <code>{@linkplain Double#toString(double) Double#toString}(value)</code>
* and counting the number of digits after the decimal separator.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static int countFractionDigits(final double value) {
return org.geotools.math.XMath.countDecimalFractionDigits(value);
}
/**
* Finds the least float greater than d (if positive == true),
* or the greatest float less than d (if positive == false).
* If NaN, returns same value. This code is an adaptation of
* {@link java.text.ChoiceFormat#nextDouble}.
*
* @todo Remove this method when we will be allowed to use Java 6.
*/
private static float next(final float f, final boolean positive) {
final int SIGN = 0x80000000;
final int POSITIVEINFINITY = 0x7F800000;
// Filter out NaN's
if (Float.isNaN(f)) {
return f;
}
// Zero's are also a special case
if (f == 0f) {
final float smallestPositiveFloat = Float.intBitsToFloat(1);
return (positive) ? smallestPositiveFloat : -smallestPositiveFloat;
}
// If entering here, d is a nonzero value.
// Hold all bits in a int for later use.
final int bits = Float.floatToIntBits(f);
// Strip off the sign bit.
int magnitude = bits & ~SIGN;
// If next float away from zero, increase magnitude.
// Else decrease magnitude
if ((bits > 0) == positive) {
if (magnitude != POSITIVEINFINITY) {
magnitude++;
}
} else {
magnitude--;
}
// Restore sign bit and return.
final int signbit = bits & SIGN;
return Float.intBitsToFloat(magnitude | signbit);
}
/**
* Finds the least float greater than <var>f</var>.
* If {@code NaN}, returns same value.
*
* @todo Remove this method when we will be allowed to use Java 6.
*/
public static float next(final float f) {
return next(f, true);
}
/**
* Finds the greatest float less than <var>f</var>.
* If {@code NaN}, returns same value.
*
* @todo Remove this method when we will be allowed to use Java 6.
*/
public static float previous(final float f) {
return next(f, false);
}
/**
* Finds the least double greater than <var>f</var>.
* If {@code NaN}, returns same value.
*
* @see java.text.ChoiceFormat#nextDouble
*
* @todo Remove this method when we will be allowed to use Java 6.
*/
public static double next(final double f) {
return ChoiceFormat.nextDouble(f);
}
/**
* Finds the greatest double less than <var>f</var>.
* If {@code NaN}, returns same value.
*
* @see java.text.ChoiceFormat#previousDouble
*
* @todo Remove this method when we will be allowed to use Java 6.
*/
public static double previous(final double f) {
return ChoiceFormat.previousDouble(f);
}
/**
* Returns the next or previous representable number. If {@code amount} is equals to
* {@code 0}, then this method returns the {@code value} unchanged. Otherwise,
* The operation performed depends on the specified {@code type}:
* <ul>
* <li><p>If the {@code type} is {@link Double}, then this method is
* equivalent to invoking {@link #previous(double)} if {@code amount} is equals to
* {@code -1}, or invoking {@link #next(double)} if {@code amount} is equals to
* {@code +1}. If {@code amount} is smaller than {@code -1} or greater
* than {@code +1}, then this method invokes {@link #previous(double)} or
* {@link #next(double)} in a loop for {@code abs(amount)} times.</p></li>
*
* <li><p>If the {@code type} is {@link Float}, then this method is
* equivalent to invoking {@link #previous(float)} if {@code amount} is equals to
* {@code -1}, or invoking {@link #next(float)} if {@code amount} is equals to
* {@code +1}. If {@code amount} is smaller than {@code -1} or greater
* than {@code +1}, then this method invokes {@link #previous(float)} or
* {@link #next(float)} in a loop for {@code abs(amount)} times.</p></li>
*
* <li><p>If the {@code type} is an {@linkplain #isInteger integer}, then invoking
* this method is equivalent to computing {@code value + amount}.</p></li>
* </ul>
*
* @param type The type. Should be the class of {@link Double}, {@link Float},
* {@link Long}, {@link Integer}, {@link Short} or {@link Byte}.
* @param value The number to rool.
* @param amount -1 to return the previous representable number,
* +1 to return the next representable number, or
* 0 to return the number with no change.
* @return One of previous or next representable number as a {@code double}.
* @throws IllegalArgumentException if {@code type} is not one of supported types.
*/
public static double rool(final Class type, double value, int amount)
throws IllegalArgumentException
{
if (Double.class.equals(type)) {
if (amount<0) {
do {
value = previous(value);
} while (++amount != 0);
} else if (amount!=0) {
do {
value = next(value);
} while (--amount != 0);
}
return value;
}
if (Float.class.equals(type)) {
float vf = (float)value;
if (amount<0) {
do {
vf = previous(vf);
} while (++amount != 0);
} else if (amount!=0) {
do {
vf = next(vf);
} while (--amount != 0);
}
return vf;
}
if (isInteger(type)) {
return value + amount;
}
throw new IllegalArgumentException(Errors.format(ErrorKeys.UNSUPPORTED_DATA_TYPE_$1, type));
}
/**
* Returns a {@link Float#NaN NaN} number for the specified index. Valid NaN numbers have
* bit fields ranging from {@code 0x7f800001} through {@code 0x7fffffff} or {@code 0xff800001}
* through {@code 0xffffffff}. The standard {@link Float#NaN} has bit fields {@code 0x7fc00000}.
*
* @param index The index, from -2097152 to 2097151 inclusive.
* @return One of the legal {@link Float#NaN NaN} values as a float.
* @throws IndexOutOfBoundsException if the specified index is out of bounds.
*
* @deprecated Moved to {@link org.geotools.math.XMath}.
*/
@Deprecated
public static float toNaN(int index) throws IndexOutOfBoundsException {
return org.geotools.math.XMath.toNaN(index);
}
/**
* Returns {@code true} if the specified {@code type} is one of real
* number types. Real number types includes {@link Float} and {@link Double}.
*
* @param type The type to test (may be {@code null}).
* @return {@code true} if {@code type} is the class {@link Float} or {@link Double}.
*
* @deprecated Moved to {@link Classes}.
*/
@Deprecated
public static boolean isReal(final Class<?> type) {
return type != null &&
Double.class.equals(type) ||
Float.class.equals(type);
}
/**
* Returns {@code true} if the specified {@code type} is one of integer types.
* Integer types includes {@link Long}, {@link Integer}, {@link Short} and {@link Byte}.
*
* @param type The type to test (may be {@code null}).
* @return {@code true} if {@code type} is the class {@link Long}, {@link Integer},
* {@link Short} or {@link Byte}.
*
* @deprecated Moved to {@link Classes}.
*/
@Deprecated
public static boolean isInteger(final Class<?> type) {
return type != null &&
Long.class.equals(type) ||
Integer.class.equals(type) ||
Short.class.equals(type) ||
Byte.class.equals(type);
}
/**
* Returns the number of bits used by number of the specified type.
*
* @param type The type (may be {@code null}).
* @return The number of bits, or 0 if unknow.
*
* @deprecated Moved to {@link Classes}.
*/
@Deprecated
public static int getBitCount(final Class<?> type) {
if (Double .class.equals(type)) return Double .SIZE;
if (Float .class.equals(type)) return Float .SIZE;
if (Long .class.equals(type)) return Long .SIZE;
if (Integer .class.equals(type)) return Integer .SIZE;
if (Short .class.equals(type)) return Short .SIZE;
if (Byte .class.equals(type)) return Byte .SIZE;
if (Character.class.equals(type)) return Character.SIZE;
if (Boolean .class.equals(type)) return 1;
return 0;
}
/**
* Change a primitive class to its wrapper (e.g. {@code double} to {@link Double}).
* If the specified class is not a primitive type, then it is returned unchanged.
*
* @param type The primitive type (may be {@code null}).
* @return The type as a wrapper.
*
* @deprecated Moved to {@link Classes}.
*/
@Deprecated
public static Class<?> primitiveToWrapper(final Class<?> type) {
if (Character.TYPE.equals(type)) return Character.class;
if (Boolean .TYPE.equals(type)) return Boolean .class;
if (Byte .TYPE.equals(type)) return Byte .class;
if (Short .TYPE.equals(type)) return Short .class;
if (Integer .TYPE.equals(type)) return Integer .class;
if (Long .TYPE.equals(type)) return Long .class;
if (Float .TYPE.equals(type)) return Float .class;
if (Double .TYPE.equals(type)) return Double .class;
return type;
}
/**
* Converts the specified string into a value object. The value object will be an instance
* of {@link Boolean}, {@link Integer}, {@link Double}, <cite>etc.</cite> according the
* specified type.
*
* @param type The requested type.
* @param value the value to parse.
* @return The value object, or {@code null} if {@code value} was null.
* @throws IllegalArgumentException if {@code type} is not a recognized type.
* @throws NumberFormatException if the string value is not parseable as a number
* of the specified type.
*
* @since 2.4
*
* @deprecated Moved to {@link Classes}.
*/
@Deprecated
@SuppressWarnings("unchecked")
public static <T> T valueOf(final Class<T> type, final String value)
throws IllegalArgumentException, NumberFormatException
{
if (value == null) {
return null;
}
if (Double .class.equals(type)) return (T) Double .valueOf(value);
if (Float .class.equals(type)) return (T) Float .valueOf(value);
if (Long .class.equals(type)) return (T) Long .valueOf(value);
if (Integer.class.equals(type)) return (T) Integer.valueOf(value);
if (Short .class.equals(type)) return (T) Short .valueOf(value);
if (Byte .class.equals(type)) return (T) Byte .valueOf(value);
if (Boolean.class.equals(type)) return (T) Boolean.valueOf(value);
throw new IllegalArgumentException(Errors.format(ErrorKeys.UNKNOW_TYPE_$1, type));
}
}