Java/Data Type/Number
Версия от 18:01, 31 мая 2010; (обсуждение)
Содержание
- 1 Check if number are in a given range
- 2 Check Number properties and convert from Number
- 3 Checks whether the String a valid Java number.
- 4 Convert to numbers
- 5 Get Digit Number String
- 6 Methods for number conversion and parsing
- 7 Provides IEEE-754r variants of NumberUtils methods.
- 8 Turns a string value into a java.lang.Number.
- 9 Various number-related routines and classes that are frequently used
Check if number are in a given range
/*
* Copyright 2008-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Check if number are in a given range
*
* @author Cedric Chabanois (cchabanois at gmail.ru)
*
*/
public class NumberInRange {
public static final BigInteger BYTE_MIN = BigInteger
.valueOf((long) Byte.MIN_VALUE);
public static final BigInteger BYTE_MAX = BigInteger
.valueOf((long) Byte.MAX_VALUE);
public static final BigInteger SHORT_MIN = BigInteger
.valueOf((long) Short.MIN_VALUE);
public static final BigInteger SHORT_MAX = BigInteger
.valueOf((long) Short.MAX_VALUE);
public static final BigInteger INTEGER_MIN = BigInteger
.valueOf((long) Integer.MIN_VALUE);
public static final BigInteger INTEGER_MAX = BigInteger
.valueOf((long) Integer.MAX_VALUE);
public static final BigInteger LONG_MIN = BigInteger
.valueOf(Long.MIN_VALUE);
public static final BigInteger LONG_MAX = BigInteger
.valueOf(Long.MAX_VALUE);
public static final BigDecimal FLOAT_MAX = new BigDecimal(Float.MAX_VALUE);
public static final BigDecimal FLOAT_MIN = new BigDecimal(-Float.MAX_VALUE);
public static final BigDecimal DOUBLE_MAX = new BigDecimal(Double.MAX_VALUE);
public static final BigDecimal DOUBLE_MIN = new BigDecimal(
-Double.MAX_VALUE);
public static boolean isInByteRange(Number number) {
return isInRange(number, BYTE_MIN, BYTE_MAX);
}
public static boolean isInShortRange(Number number) {
return isInRange(number, SHORT_MIN, SHORT_MAX);
}
public static boolean isInIntegerRange(Number number) {
return isInRange(number, INTEGER_MIN, INTEGER_MAX);
}
public static boolean isInLongRange(Number number) {
return isInRange(number, LONG_MIN, LONG_MAX);
}
public static boolean isInRange(Number number, BigInteger min,
BigInteger max) {
try {
BigInteger bigInteger = null;
if (number instanceof Byte || number instanceof Short
|| number instanceof Integer || number instanceof Long) {
bigInteger = BigInteger.valueOf(number.longValue());
} else if (number instanceof Float || number instanceof Double) {
bigInteger = new BigDecimal(number.doubleValue())
.toBigInteger();
} else if (number instanceof BigInteger) {
bigInteger = (BigInteger) number;
} else if (number instanceof BigDecimal) {
bigInteger = ((BigDecimal) number).toBigInteger();
} else {
// not a standard number
bigInteger = new BigDecimal(number.doubleValue())
.toBigInteger();
}
return max.rupareTo(bigInteger) >= 0
&& min.rupareTo(bigInteger) <= 0;
} catch (NumberFormatException e) {
return false;
}
}
public static boolean isInRange(Number number, BigDecimal min,
BigDecimal max) {
try {
BigDecimal bigDecimal = null;
if (number instanceof Byte || number instanceof Short
|| number instanceof Integer || number instanceof Long) {
bigDecimal = new BigDecimal(number.longValue());
} else if (number instanceof Float || number instanceof Double) {
bigDecimal = new BigDecimal(number.doubleValue());
} else if (number instanceof BigInteger) {
bigDecimal = new BigDecimal((BigInteger) number);
} else if (number instanceof BigDecimal) {
bigDecimal = (BigDecimal) number;
} else {
bigDecimal = new BigDecimal(number.doubleValue());
}
return max.rupareTo(bigDecimal) >= 0
&& min.rupareTo(bigDecimal) <= 0;
} catch (NumberFormatException e) {
return false;
}
}
public static boolean isInFloatRange(Number number) {
return isInRange(number, FLOAT_MIN, FLOAT_MAX);
}
public static boolean isInDoubleRange(Number number) {
return isInRange(number, DOUBLE_MIN, DOUBLE_MAX);
}
}
Check Number properties and convert from Number
/**
* Copyright 2004, 2005, 2006 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Number utilities.
*
* Allows to convert between different <code>java.lang.Number</code>
* implementations with a minimum of lost information regarding the
* value of the represented number. Additionally, a few number tests
* are implemented and exact comparisons of arbitrary numbers may be
* performed.
*
* NOTE: Though some of the methods may give more or less useful results
* for custom number implementations, they are intended to work only
* with the predefined types (i.e., <code>Byte, Short, Integer, Long,
* Float, Double, BigInteger, BigDecimal</code>).
*
* @author Oliver Stuhr
*/
public class NumberUtils {
/**
* Answers <code>true</code> iff the given number is an instance of
* <code>java.math.BigDecimal</code> or <code>java.math.BigInteger</code>.
*
* @param number
* @return boolean
*/
public static boolean isBig(Number number) {
return number instanceof BigDecimal || number instanceof BigInteger;
}
/**
* Answers <code>true</code> iff the given number is an instance of
* <code>Byte</code>, <code>Short</code>, <code>Integer</code> or <code>Long</code>.
*
* @param number
* @return boolean
*/
public static boolean isLongCompatible(Number number) {
return number instanceof Byte || number instanceof Short || number instanceof Integer || number instanceof Long;
}
/**
* Answers <code>true</code> iff the given number is an instance of
* <code>Float</code> or <code>Double</code>.
*
* @param number
* @return boolean
*/
public static boolean isDoubleCompatible(Number number) {
return number instanceof Float || number instanceof Double;
}
/**
* Answers <code>true</code> iff the given number is infinite (i.e., is
* a <code>Float</code> or <code>Double</code> containing one of the
* predefined constant values representing positive or negative infinity).
*
* @param number
* @return boolean
*/
public static boolean isInfinite(Number number) {
if (number instanceof Double && ((Double)number).isInfinite())
return true;
if (number instanceof Float && ((Float)number).isInfinite())
return true;
return false;
}
/**
* Answers <code>true</code> iff the given number is "not a number"
* (i.e., is a <code>Float</code> or <code>Double</code> containing
* one of the predefined constant values representing <code>NaN</code>).
*
* @param number
* @return boolean
*/
public static boolean isNaN(Number number) {
if (number instanceof Double && ((Double)number).isNaN())
return true;
if (number instanceof Float && ((Float)number).isNaN())
return true;
return false;
}
/**
* Answers the signum function of the given number
* (i.e., <code>-1</code> if it is negative, <code>0</code>
* if it is zero and <code>1</code> if it is positive).
*
* @param number
* @return int
* @throws ArithmeticException The given number is <code>null</code> or "not a number".
*/
public static int signum(Number number) throws ArithmeticException {
if (number == null || isNaN(number))
throw new ArithmeticException("Argument must not be null or NaN.");
if (isLongCompatible(number)) {
long value = number.longValue();
return value < 0 ? -1 : value == 0 ? 0 : 1;
} else if (number instanceof BigInteger)
return ((BigInteger)number).signum();
else if (number instanceof BigDecimal)
return ((BigDecimal)number).signum();
else { // => isDoubleCompatible(number) or unknown Number type
double value = number.doubleValue();
return value < 0 ? -1 : value == 0 ? 0 : 1;
}
}
/**
* Converts the given number to a <code>Byte</code> (by using <code>byteValue()</code>).
*
* @param number
* @return java.lang.Byte
* @throws IllegalArgumentException The given number is "not a number" or infinite.
*/
public static Byte toByte(Number number) throws IllegalArgumentException {
if (number == null || number instanceof Byte)
return (Byte)number;
if (isNaN(number) || isInfinite(number))
throw new IllegalArgumentException("Argument must not be NaN or infinite.");
return new Byte(number.byteValue());
}
/**
* Converts the given number to a <code>Short</code> (by using <code>shortValue()</code>).
*
* @param number
* @return java.lang.Short
* @throws IllegalArgumentException The given number is "not a number" or infinite.
*/
public static Short toShort(Number number) throws IllegalArgumentException {
if (number == null || number instanceof Short)
return (Short)number;
if (isNaN(number) || isInfinite(number))
throw new IllegalArgumentException("Argument must not be NaN or infinite.");
return new Short(number.shortValue());
}
/**
* Converts the given number to a <code>Integer</code> (by using <code>intValue()</code>).
*
* @param number
* @return java.lang.Integer
* @throws IllegalArgumentException The given number is "not a number" or infinite.
*/
public static Integer toInteger(Number number) throws IllegalArgumentException {
if (number == null || number instanceof Integer)
return (Integer)number;
if (isNaN(number) || isInfinite(number))
throw new IllegalArgumentException("Argument must not be NaN or infinite.");
return new Integer(number.intValue());
}
/**
* Converts the given number to a <code>Long</code> (by using <code>longValue()</code>).
*
* @param number
* @return java.lang.Long
* @throws IllegalArgumentException The given number is "not a number" or infinite.
*/
public static Long toLong(Number number) throws IllegalArgumentException {
if (number == null || number instanceof Long)
return (Long)number;
if (isNaN(number) || isInfinite(number))
throw new IllegalArgumentException("Argument must not be NaN or infinite.");
return new Long(number.longValue());
}
/**
* Converts the given number to a <code>Float</code> (by using <code>floatValue()</code>).
*
* @param number
* @return java.lang.Float
*/
public static Float toFloat(Number number) {
return number == null || number instanceof Float ? (Float)number : new Float(number.floatValue());
}
/**
* Converts the given number to a <code>Double</code> (by using <code>doubleValue()</code>).
*
* @param number
* @return java.lang.Double
*/
public static Double toDouble(Number number) {
return number == null || number instanceof Double ? (Double)number : new Double(number.doubleValue());
}
/**
* Converts the given number to a <code>java.math.BigInteger</code>.
*
* @param number
* @return java.math.BigInteger
* @throws IllegalArgumentException The given number is "not a number" or infinite.
*/
public static BigInteger toBigInteger(Number number) throws IllegalArgumentException {
if (number == null || number instanceof BigInteger)
return (BigInteger)number;
if (number instanceof BigDecimal)
return ((BigDecimal)number).toBigInteger();
if (isDoubleCompatible(number)) {
if (isNaN(number) || isInfinite(number))
throw new IllegalArgumentException("Argument must not be NaN or infinite.");
return new BigDecimal(number.toString()).toBigInteger();
} // => isLongCompatible(number) or unknown Number type
return BigInteger.valueOf(number.longValue());
}
/**
* Converts the given number to a <code>java.math.BigDecimal</code>.
*
* @param number
* @return java.math.BigDecimal
* @throws IllegalArgumentException The given number is "not a number" or infinite.
*/
public static BigDecimal toBigDecimal(Number number) throws IllegalArgumentException {
if (number == null || number instanceof BigDecimal)
return (BigDecimal)number;
if (number instanceof BigInteger)
return new BigDecimal((BigInteger)number);
if (isDoubleCompatible(number)) {
if (isNaN(number) || isInfinite(number))
throw new IllegalArgumentException("Argument must not be NaN or infinite.");
return new BigDecimal(number.toString());
}
if (isLongCompatible(number))
return BigDecimal.valueOf(number.longValue());
// => unknown Number type
return new BigDecimal(String.valueOf(number.doubleValue()));
}
/**
* Compares the first number to the second one numerically and
* returns an integer depending on the comparison result:
* a negative value if the first number is the smaller one,
* a zero value if they are equal, and
* a positive value if the first number is the larger one.
*
* The main strategy goes like follows:
* 1. If one of the arguments is <code>null</code> or "not a number",
* throw an exception.
* 2. If both values are "long compatible", compare their <code>longValue()</code>
* using the usual comparison operators for primitive types (<, ==, >).
* 3. If both values are "double compatible", compare their <code>doubleValue()</code>
* using the usual comparison operators for primitive types (<, ==, >).
* 4. If one of the values is infinite (and the other is finite),
* determine the result depending on the sign of the infinite value.
* 5. Otherwise convert both values to <code>java.math.BigDecimal</code> and
* return the result of the <code>BigDecimal.rupareTo(BigDecimal)</code> method.
*
* As a consequence, the method is not suitable to implement a
* <code>java.util.ruparator</code> for numbers. To achieve this,
* one had to accept "not a number" arguments and place them somewhere
* in the row of numbers (probably at the upper end, i.e. larger than
* positive infinity, as <code>Double.rupare(double, double)</code>
* does it).
* So the behavior of this method is like that of the comparison
* operator for primitive types and not like that of the related
* <code>compareTo(...)</code> methods. Besides the handling of
* "not a number" values this makes a difference, when comparing
* the float or double values <code>-0.0</code> and <code>0.0</code>:
* again, like the operators, we consider them as equal (whereas
* according to <code>Double.rupareTo(...)</code> <code>-0.0</code>
* is less than <code>0.0</code>).
*
* @param first
* @param second
* @return int
* @throws ArithmeticException One or both of the given numbers is <code>null</code> or "not a number".
*/
public static int compare(Number first, Number second) throws ArithmeticException {
if (first == null || second == null || isNaN(first) || isNaN(second))
throw new ArithmeticException("Arguments must not be null or NaN.");
int result = -2;
if (isLongCompatible(first) && isLongCompatible(second)) {
long v1 = first.longValue(), v2 = second.longValue();
result = v1 < v2 ? -1 : v1 == v2 ? 0 : v1 > v2 ? 1 : 2;
} else if (isDoubleCompatible(first) && isDoubleCompatible(second)) {
double v1 = first.doubleValue(), v2 = second.doubleValue();
result = v1 < v2 ? -1 : v1 == v2 ? 0 : v1 > v2 ? 1 : 2;
}
if (result == 2) // should not happen
throw new ArithmeticException("Arguments " + first + " and " + second + " are not comparable.");
if (result > -2)
return result;
if (isInfinite(first)) // => second is finite
return first.doubleValue() == Double.NEGATIVE_INFINITY ? -1 : 1;
if (isInfinite(second)) // => first is finite
return second.doubleValue() == Double.POSITIVE_INFINITY ? -1 : 1;
return toBigDecimal(first).rupareTo(toBigDecimal(second));
}
}
Checks whether the String a valid Java number.
/*
* 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.
*/
import java.math.BigDecimal;
import java.math.BigInteger;
public final class NumberUtils {
// Empty checks
//-----------------------------------------------------------------------
/**
* <p>Checks if a String is empty ("") or null.</p>
*
* <pre>
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty("") = true
* StringUtils.isEmpty(" ") = false
* StringUtils.isEmpty("bob") = false
* StringUtils.isEmpty(" bob ") = false
* </pre>
*
* <p>NOTE: This method changed in Lang version 2.0.
* It no longer trims the String.
* That functionality is available in isBlank().</p>
*
* @param str the String to check, may be null
* @return <code>true</code> if the String is empty or null
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
/**
* <p>Checks whether the String a valid Java number.</p>
*
* <p>Valid numbers include hexadecimal marked with the <code>0x</code>
* qualifier, scientific notation and numbers marked with a type
* qualifier (e.g. 123L).</p>
*
* <p><code>Null</code> and empty String will return
* <code>false</code>.</p>
*
* @param str the <code>String</code> to check
* @return <code>true</code> if the string is a correctly formatted number
*/
public static boolean isNumber(String str) {
if (isEmpty(str)) {
return false;
}
char[] chars = str.toCharArray();
int sz = chars.length;
boolean hasExp = false;
boolean hasDecPoint = false;
boolean allowSigns = false;
boolean foundDigit = false;
// deal with any possible sign up front
int start = (chars[0] == "-") ? 1 : 0;
if (sz > start + 1) {
if (chars[start] == "0" && chars[start + 1] == "x") {
int i = start + 2;
if (i == sz) {
return false; // str == "0x"
}
// checking hex (it can"t be anything else)
for (; i < chars.length; i++) {
if ((chars[i] < "0" || chars[i] > "9")
&& (chars[i] < "a" || chars[i] > "f")
&& (chars[i] < "A" || chars[i] > "F")) {
return false;
}
}
return true;
}
}
sz--; // don"t want to loop to the last char, check it afterwords
// for type qualifiers
int i = start;
// loop to the next to last char or to the last char if we need another digit to
// make a valid number (e.g. chars[0..5] = "1234E")
while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
if (chars[i] >= "0" && chars[i] <= "9") {
foundDigit = true;
allowSigns = false;
} else if (chars[i] == ".") {
if (hasDecPoint || hasExp) {
// two decimal points or dec in exponent
return false;
}
hasDecPoint = true;
} else if (chars[i] == "e" || chars[i] == "E") {
// we"ve already taken care of hex.
if (hasExp) {
// two E"s
return false;
}
if (!foundDigit) {
return false;
}
hasExp = true;
allowSigns = true;
} else if (chars[i] == "+" || chars[i] == "-") {
if (!allowSigns) {
return false;
}
allowSigns = false;
foundDigit = false; // we need a digit after the E
} else {
return false;
}
i++;
}
if (i < chars.length) {
if (chars[i] >= "0" && chars[i] <= "9") {
// no type qualifier, OK
return true;
}
if (chars[i] == "e" || chars[i] == "E") {
// can"t have an E at the last byte
return false;
}
if (!allowSigns
&& (chars[i] == "d"
|| chars[i] == "D"
|| chars[i] == "f"
|| chars[i] == "F")) {
return foundDigit;
}
if (chars[i] == "l"
|| chars[i] == "L") {
// not allowing L with an exponent
return foundDigit && !hasExp;
}
// last character is illegal
return false;
}
// allowSigns is true iff the val ends in "E"
// found digit it to make sure weird stuff like "." and "1E-" doesn"t pass
return !allowSigns && foundDigit;
}
}
Convert to numbers
/*
* Copyright Javelin Software, All rights reserved.
*/
import java.math.*;
/**
* The NumberUtil is used as a Utility Class for Numbers
* classes such as Integers and Doubles etc.
*
* @author Robin Sharp
*/
public class NumberUtil
{
/**
* Returns the BigDecimal value n with trailing
* zeroes removed.
*/
public static BigDecimal trim(BigDecimal n)
{
try
{
while (true)
{
n = n.setScale(n.scale()-1);
}
}
catch (ArithmeticException e)
{
// no more trailing zeroes so exit.
}
return n;
}
/**
* Returns the BigDecimal value n with exactly
* "prec" decimal places.
* Zeroes are padded to the right of the decimal
* point if necessary.
*/
public static BigDecimal format(BigDecimal n, int prec)
{
return n.setScale(prec, BigDecimal.ROUND_HALF_UP);
}
/**
* Convert an Object of type Class to a Number.
*/
public static Object toObject( Class clazz, Object value )
{
if( value == null ) return null;
if( clazz == null ) return value;
if( Boolean.class.isAssignableFrom( clazz ) ) return toBoolean( value );
if( Byte.class.isAssignableFrom( clazz ) ) return toByte( value );
if( Short.class.isAssignableFrom( clazz ) ) return toShort( value );
if( Integer.class.isAssignableFrom( clazz ) ) return toInteger( value );
if( Long.class.isAssignableFrom( clazz ) ) return toLong( value );
if( Float.class.isAssignableFrom( clazz ) ) return toFloat( value );
if( Double.class.isAssignableFrom( clazz ) ) return toDouble( value );
if( BigInteger.class.isAssignableFrom( clazz ) ) return toBigInteger( value );
if( BigDecimal.class.isAssignableFrom( clazz ) ) return toBigDecimal( value );
return value;
}
/**
* Convert a Sting "TRUE" to 1, otherwise 0.
*/
public static int valueOfBoolean( String string )
{
return string != null && "TRUE".equalsIgnoreCase( string ) ? 1 : 0;
}
/**
* Optimisation Code
*/
public static Boolean getBoolean( boolean bool )
{
return bool ? Boolean.TRUE : Boolean.FALSE;
}
/**
* Convert an Object to a Boolean.
*/
public static Boolean toBoolean( Object value )
{
if( value == null ) return null;
if( value instanceof Boolean ) return (Boolean)value;
if( "TRUE".equalsIgnoreCase( value.toString() ) ) return Boolean.TRUE;
if( "".equals( value.toString() ) ) return null;
return Boolean.FALSE;
}
/**
* Convert an Object to an Integer.
*/
public static Integer toInteger( Object value )
{
if( value == null ) return null;
if( value instanceof Integer ) return (Integer)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new Integer( (String)value );
}
if( value instanceof Number ) return new Integer( ((Number)value).intValue() );
return new Integer( value.toString() );
}
/**
* Convert an Object to a Long.
*/
public static Long toLong( Object value )
{
if( value == null ) return null;
if( value instanceof Long ) return (Long)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new Long( (String)value );
}
if( value instanceof Number ) return new Long( ((Number)value).shortValue() );
return new Long( value.toString() );
}
/**
* Convert an Object to a Short.
*/
public static Short toShort( Object value )
{
if( value == null ) return null;
if( value instanceof Short ) return (Short)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new Short( (String)value );
}
if( value instanceof Number ) return new Short( ((Number)value).shortValue() );
return new Short( value.toString() );
}
/**
* Convert an Object to a Byte.
*/
public static Byte toByte( Object value )
{
if( value == null ) return null;
if( value instanceof Byte ) return (Byte)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new Byte( (String)value );
}
if( value instanceof Number ) return new Byte( ((Number)value).byteValue() );
return new Byte( value.toString() );
}
/**
* Convert an Object to a Float.
*/
public static Float toFloat( Object value )
{
if( value == null ) return null;
if( value instanceof Float ) return (Float)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new Float( (String)value );
}
if( value instanceof Number ) return new Float( ((Number)value).floatValue() );
return new Float( value.toString() );
}
/**
* Convert an Object to a Double.
*/
public static Double toDouble( Object value )
{
if( value == null ) return null;
if( value instanceof Double ) return (Double)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new Double( (String)value );
}
if( value instanceof Number ) return new Double( ((Number)value).doubleValue() );
return new Double( value.toString() );
}
/**
* Convert an Object to a BigInteger.
*/
public static BigInteger toBigInteger( Object value )
{
if( value == null ) return null;
if( value instanceof BigInteger ) return (BigInteger)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new BigInteger( (String)value );
}
return new BigInteger( value.toString() );
}
/**
* Convert an Object to a BigDecimal.
*/
public static BigDecimal toBigDecimal( Object value )
{
if( value == null ) return null;
if( value instanceof BigDecimal ) return (BigDecimal)value;
if( value instanceof String )
{
if( "".equals( (String)value ) ) return null;
return new BigDecimal( (String)value );
}
if( value instanceof Number ) return new BigDecimal( ((Number)value).doubleValue() );
return new BigDecimal( value.toString() );
}
/**
* Convert an Object to a Boolean.
*/
public static boolean booleanValue( Object value )
{
if( value == null ) return false;
if( value instanceof Boolean ) return ((Boolean)value).booleanValue();
if( value instanceof Number ) return ((Number)value).intValue() != 0;
return "TRUE".equalsIgnoreCase( value.toString() );
}
/**
* Convert an Object to an int, or 0 if it is null.
*/
public static int intValue( Object value )
{
if( value == null ) return 0;
return toInteger( value ).intValue();
}
/**
* Convert an Object to a long, or 0 if it is null.
*/
public static long longValue( Object value )
{
if( value == null ) return 0L;
return toLong( value ).longValue();
}
/**
* Convert an Object to a short, or 0 if it is null.
*/
public static short shortValue( Object value )
{
if( value == null ) return 0;
return toShort( value ).shortValue();
}
/**
* Convert an Object to a byte, or 0 if it is null.
*/
public static byte byteValue( Object value )
{
if( value == null ) return 0;
return toByte( value ).byteValue();
}
/**
* Convert an Object to a float, or 0 if it is null.
*/
public static float floatValue( Object value )
{
if( value == null ) return 0.0f;
return toFloat( value ).floatValue();
}
/**
* Convert an Object to a double, or 0 if it is null.
*/
public static double doubleValue( Object value )
{
if( value == null ) return 0.0;
return toDouble( value ).doubleValue();
}
}
Get Digit Number String
/*
* Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
*
* Project: OpenSubsystems
*
* $Id: NumberUtils.java,v 1.9 2007/01/07 06:14:01 bastafidli Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.text.NumberFormat;
/**
* Collection of useful utilities to work with numbers.
*
* @version $Id: NumberUtils.java,v 1.9 2007/01/07 06:14:01 bastafidli Exp $
* @author Peter Satury
* @code.reviewer Miro Halas
* @code.reviewed Initial revision
*/
public final class NumberUtils
{
// Constants ////////////////////////////////////////////////////////////////
/**
* Static array used to append leading 0 chars to file name constructed from
* number.
*/
protected static final char[] ZEROCHARS = {"0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
"0", "0", "0", "0", "0", "0", "0", "0", "0", "0",
};
// Cached values ////////////////////////////////////////////////////////////
/**
* static Number format for no Exponent
*/
public static final NumberFormat NFFORMAT;
/**
* static Number format for no Exponent for editing
*/
public static final NumberFormat NFFORMATEDIT;
/**
* static Number format for Currency
*/
public static final NumberFormat NFCURRENCYFORMAT;
/**
* static Number format for Currency for editing
*/
public static final NumberFormat NFCURRENCYFORMATEDIT;
// Constructors /////////////////////////////////////////////////////////////
/**
* Static initializer.
*/
static
{
NFFORMAT = NumberFormat.getNumberInstance();
NFFORMAT.setMaximumFractionDigits(20);
NFFORMATEDIT = NumberFormat.getNumberInstance();
NFFORMATEDIT.setMaximumFractionDigits(20);
NFFORMATEDIT.setGroupingUsed(false);
NFCURRENCYFORMAT = NumberFormat.getNumberInstance();
NFCURRENCYFORMAT.setMaximumFractionDigits(2);
NFCURRENCYFORMAT.setMinimumFractionDigits(2);
NFCURRENCYFORMATEDIT = NumberFormat.getNumberInstance();
NFCURRENCYFORMATEDIT.setMaximumFractionDigits(2);
NFCURRENCYFORMATEDIT.setMinimumFractionDigits(2);
NFCURRENCYFORMATEDIT.setGroupingUsed(false);
}
/**
* Private constructor since this class cannot be instantiated
*/
private NumberUtils(
)
{
// Do nothing
}
// Public methods ///////////////////////////////////////////////////////////
/**
* Method to make Exponention
*
* @param iBbase - base of Exponention [1..]
* @param iExponent - exponent of Exponention [0..14]
* @return long - result of Exponention
* @throws IllegalArgumentException - in case of arguments out of valid range
*/
public static long exponentiate(
int iBbase,
int iExponent
) throws IllegalArgumentException
{
if (iExponent > 14 || iExponent < 0)
{
throw new IllegalArgumentException(
"Exponent could not be greater then 14 and lower then 0");
}
if (iBbase < 1)
{
throw new IllegalArgumentException(
"Exponentiate base could not be lower then 1");
}
long lReturn = 1;
for (int iCounter = 0; iCounter < iExponent; iCounter++)
{
try
{
lReturn = lReturn * iBbase;
}
catch (Exception eExc)
{
throw new IllegalArgumentException(
"Exponentiate arguments too high");
}
}
return lReturn;
}
/**
* Method to make specified length digit number string representation from particular
* input number.
* For example, if there will be send input number 32 and digit lenhth = 8, output
* will be string "00000032"
*
* @param iInputNumber - input number that will be converted into 8 digit number
* string representation
* @param iDigitLength - length of the output digit number string
*
* @return String - digit number string representation
*/
public static String getDigitNumberString(
int iInputNumber,
int iDigitLength
)
{
StringBuffer idString = new StringBuffer(Integer.toString(iInputNumber));
if (iDigitLength - idString.length() > 0)
{
idString.insert(0, ZEROCHARS, 0, iDigitLength - idString.length());
}
return idString.toString();
}
}
Methods for number conversion and parsing
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.NumberFormat;
import java.text.ParseException;
/**
* Miscellaneous utility methods for number conversion and parsing.
* Mainly for internal use within the framework; consider Jakarta"s
* Commons Lang for a more comprehensive suite of string utilities.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @since 1.1.2
*/
public abstract class NumberUtils {
/**
* Convert the given number into an instance of the given target class.
* @param number the number to convert
* @param targetClass the target class to convert to
* @return the converted number
* @throws IllegalArgumentException if the target class is not supported
* (i.e. not a standard Number subclass as included in the JDK)
* @see java.lang.Byte
* @see java.lang.Short
* @see java.lang.Integer
* @see java.lang.Long
* @see java.math.BigInteger
* @see java.lang.Float
* @see java.lang.Double
* @see java.math.BigDecimal
*/
public static Number convertNumberToTargetClass(Number number, Class targetClass)
throws IllegalArgumentException {
if (targetClass.isInstance(number)) {
return number;
}
else if (targetClass.equals(Byte.class)) {
long value = number.longValue();
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
raiseOverflowException(number, targetClass);
}
return new Byte(number.byteValue());
}
else if (targetClass.equals(Short.class)) {
long value = number.longValue();
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
raiseOverflowException(number, targetClass);
}
return new Short(number.shortValue());
}
else if (targetClass.equals(Integer.class)) {
long value = number.longValue();
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
raiseOverflowException(number, targetClass);
}
return new Integer(number.intValue());
}
else if (targetClass.equals(Long.class)) {
return new Long(number.longValue());
}
else if (targetClass.equals(Float.class)) {
return new Float(number.floatValue());
}
else if (targetClass.equals(Double.class)) {
return new Double(number.doubleValue());
}
else if (targetClass.equals(BigInteger.class)) {
return BigInteger.valueOf(number.longValue());
}
else if (targetClass.equals(BigDecimal.class)) {
// using BigDecimal(String) here, to avoid unpredictability of BigDecimal(double)
// (see BigDecimal javadoc for details)
return new BigDecimal(number.toString());
}
else {
throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" +
number.getClass().getName() + "] to unknown target class [" + targetClass.getName() + "]");
}
}
/**
* Raise an overflow exception for the given number and target class.
* @param number the number we tried to convert
* @param targetClass the target class we tried to convert to
*/
private static void raiseOverflowException(Number number, Class targetClass) {
throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" +
number.getClass().getName() + "] to target class [" + targetClass.getName() + "]: overflow");
}
/**
* Parse the given text into a number instance of the given target class,
* using the corresponding default <code>decode</code> methods. Trims the
* input <code>String</code> before attempting to parse the number. Supports
* numbers in hex format (with leading 0x) and in octal format (with leading 0).
* @param text the text to convert
* @param targetClass the target class to parse into
* @return the parsed number
* @throws IllegalArgumentException if the target class is not supported
* (i.e. not a standard Number subclass as included in the JDK)
* @see java.lang.Byte#decode
* @see java.lang.Short#decode
* @see java.lang.Integer#decode
* @see java.lang.Long#decode
* @see #decodeBigInteger(String)
* @see java.lang.Float#valueOf
* @see java.lang.Double#valueOf
* @see java.math.BigDecimal#BigDecimal(String)
*/
public static Number parseNumber(String text, Class targetClass) {
String trimmed = text.trim();
if (targetClass.equals(Byte.class)) {
return Byte.decode(trimmed);
}
else if (targetClass.equals(Short.class)) {
return Short.decode(trimmed);
}
else if (targetClass.equals(Integer.class)) {
return Integer.decode(trimmed);
}
else if (targetClass.equals(Long.class)) {
return Long.decode(trimmed);
}
else if (targetClass.equals(BigInteger.class)) {
return decodeBigInteger(trimmed);
}
else if (targetClass.equals(Float.class)) {
return Float.valueOf(trimmed);
}
else if (targetClass.equals(Double.class)) {
return Double.valueOf(trimmed);
}
else if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) {
return new BigDecimal(trimmed);
}
else {
throw new IllegalArgumentException(
"Cannot convert String [" + text + "] to target class [" + targetClass.getName() + "]");
}
}
/**
* Parse the given text into a number instance of the given target class,
* using the given NumberFormat. Trims the input <code>String</code>
* before attempting to parse the number.
* @param text the text to convert
* @param targetClass the target class to parse into
* @param numberFormat the NumberFormat to use for parsing (if <code>null</code>,
* this method falls back to <code>parseNumber(String, Class)</code>)
* @return the parsed number
* @throws IllegalArgumentException if the target class is not supported
* (i.e. not a standard Number subclass as included in the JDK)
* @see java.text.NumberFormat#parse
* @see #convertNumberToTargetClass
* @see #parseNumber(String, Class)
*/
public static Number parseNumber(String text, Class targetClass, NumberFormat numberFormat) {
if (numberFormat != null) {
try {
Number number = numberFormat.parse(text.trim());
return convertNumberToTargetClass(number, targetClass);
}
catch (ParseException ex) {
throw new IllegalArgumentException(ex.getMessage());
}
}
else {
return parseNumber(text, targetClass);
}
}
/**
* Decode a {@link java.math.BigInteger} from a {@link String} value.
* Supports decimal, hex and octal notation.
* @see BigInteger#BigInteger(String, int)
*/
private static BigInteger decodeBigInteger(String value) {
int radix = 10;
int index = 0;
boolean negative = false;
// Handle minus sign, if present.
if (value.startsWith("-")) {
negative = true;
index++;
}
// Handle radix specifier, if present.
if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
index += 2;
radix = 16;
}
else if (value.startsWith("#", index)) {
index++;
radix = 16;
}
else if (value.startsWith("0", index) && value.length() > 1 + index) {
index++;
radix = 8;
}
BigInteger result = new BigInteger(value.substring(index), radix);
return (negative ? result.negate() : result);
}
}
Provides IEEE-754r variants of NumberUtils methods.
/*
* 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.
*/
/**
* <p>Provides IEEE-754r variants of NumberUtils methods. </p>
*
* <p>See: </p>
*
* @since 2.4
* @version $Id: IEEE754rUtils.java 634088 2008-03-06 00:06:05Z niallp $
*/
public class IEEE754rUtils {
/**
* <p>Returns the minimum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static double min(double[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
double min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* <p>Returns the minimum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static float min(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
float min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* <p>Gets the minimum of three <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static double min(double a, double b, double c) {
return min(min(a, b), c);
}
/**
* <p>Gets the minimum of two <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static double min(double a, double b) {
if(Double.isNaN(a)) {
return b;
} else
if(Double.isNaN(b)) {
return a;
} else {
return Math.min(a, b);
}
}
/**
* <p>Gets the minimum of three <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static float min(float a, float b, float c) {
return min(min(a, b), c);
}
/**
* <p>Gets the minimum of two <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static float min(float a, float b) {
if(Float.isNaN(a)) {
return b;
} else
if(Float.isNaN(b)) {
return a;
} else {
return Math.min(a, b);
}
}
/**
* <p>Returns the maximum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static double max(double[] array) {
// Validates input
if (array== null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
double max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* <p>Returns the maximum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static float max(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
float max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* <p>Gets the maximum of three <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static double max(double a, double b, double c) {
return max(max(a, b), c);
}
/**
* <p>Gets the maximum of two <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static double max(double a, double b) {
if(Double.isNaN(a)) {
return b;
} else
if(Double.isNaN(b)) {
return a;
} else {
return Math.max(a, b);
}
}
/**
* <p>Gets the maximum of three <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static float max(float a, float b, float c) {
return max(max(a, b), c);
}
/**
* <p>Gets the maximum of two <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static float max(float a, float b) {
if(Float.isNaN(a)) {
return b;
} else
if(Float.isNaN(b)) {
return a;
} else {
return Math.max(a, b);
}
}
}
Turns a string value into a java.lang.Number.
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* 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.
*/
/**
* Contains useful helper methods for classes within this package.
*
* @author John Keyes (john at integralsource.ru)
* @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $
*/
public class Main {
//--------------------------------------------------------------------
// must handle Long, Float, Integer, Float, Short,
// BigDecimal, BigInteger and Byte
// useful methods:
// Byte.decode(String)
// Byte.valueOf(String,int radix)
// Byte.valueOf(String)
// Double.valueOf(String)
// Float.valueOf(String)
// new Float(String)
// Integer.valueOf(String,int radix)
// Integer.valueOf(String)
// Integer.decode(String)
// Integer.getInteger(String)
// Integer.getInteger(String,int val)
// Integer.getInteger(String,Integer val)
// new Integer(String)
// new Double(String)
// new Byte(String)
// new Long(String)
// Long.getLong(String)
// Long.getLong(String,int)
// Long.getLong(String,Integer)
// Long.valueOf(String,int)
// Long.valueOf(String)
// new Short(String)
// Short.decode(String)
// Short.valueOf(String,int)
// Short.valueOf(String)
// new BigDecimal(String)
// new BigInteger(String)
// new BigInteger(String,int radix)
// Possible inputs:
// 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
// plus minus everything. Prolly more. A lot are not separable.
/**
* <p>Turns a string value into a java.lang.Number.</p>
*
* <p>First, the value is examined for a type qualifier on the end
* (<code>"f","F","d","D","l","L"</code>). If it is found, it starts
* trying to create successively larger types from the type specified
* until one is found that can hold the value.</p>
*
* <p>If a type specifier is not found, it will check for a decimal point
* and then try successively larger types from <code>Integer</code> to
* <code>BigInteger</code> and from <code>Float</code> to
* <code>BigDecimal</code>.</p>
*
* <p>If the string starts with <code>0x</code> or <code>-0x</code>, it
* will be interpreted as a hexadecimal integer. Values with leading
* <code>0</code>"s will not be interpreted as octal.</p>
*
* @param val String containing a number
* @return Number created from the string
* @throws NumberFormatException if the value cannot be converted
*/
public static Number createNumber(String val) throws NumberFormatException {
if (val == null) {
return null;
}
if (val.length() == 0) {
throw new NumberFormatException("\"\" is not a valid number.");
}
if (val.startsWith("--")) {
// this is protection for poorness in java.lang.BigDecimal.
// it accepts this as a legal value, but it does not appear
// to be in specification of class. OS X Java parses it to
// a wrong value.
return null;
}
if (val.startsWith("0x") || val.startsWith("-0x")) {
return createInteger(val);
}
char lastChar = val.charAt(val.length() - 1);
String mant;
String dec;
String exp;
int decPos = val.indexOf(".");
int expPos = val.indexOf("e") + val.indexOf("E") + 1;
if (decPos > -1) {
if (expPos > -1) {
if (expPos < decPos) {
throw new NumberFormatException(val + " is not a valid number.");
}
dec = val.substring(decPos + 1, expPos);
} else {
dec = val.substring(decPos + 1);
}
mant = val.substring(0, decPos);
} else {
if (expPos > -1) {
mant = val.substring(0, expPos);
} else {
mant = val;
}
dec = null;
}
if (!Character.isDigit(lastChar)) {
if (expPos > -1 && expPos < val.length() - 1) {
exp = val.substring(expPos + 1, val.length() - 1);
} else {
exp = null;
}
//Requesting a specific type..
String numeric = val.substring(0, val.length() - 1);
boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
switch (lastChar) {
case "l" :
case "L" :
if (dec == null
&& exp == null
&& (numeric.charAt(0) == "-" && isDigits(numeric.substring(1)) || isDigits(numeric))) {
try {
return createLong(numeric);
} catch (NumberFormatException nfe) {
//Too big for a long
}
return createBigInteger(numeric);
}
throw new NumberFormatException(val + " is not a valid number.");
case "f" :
case "F" :
try {
Float f = createFloat(numeric);
if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
//If it"s too big for a float or the float value = 0 and the string
//has non-zeros in it, then float does not have the precision we want
return f;
}
} catch (NumberFormatException e) {
// ignore the bad number
}
//Fall through
case "d" :
case "D" :
try {
Double d = createDouble(numeric);
if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {
return d;
}
} catch (NumberFormatException nfe) {
// empty catch
}
try {
return createBigDecimal(numeric);
} catch (NumberFormatException e) {
// empty catch
}
//Fall through
default :
throw new NumberFormatException(val + " is not a valid number.");
}
} else {
//User doesn"t have a preference on the return type, so let"s start
//small and go from there...
if (expPos > -1 && expPos < val.length() - 1) {
exp = val.substring(expPos + 1, val.length());
} else {
exp = null;
}
if (dec == null && exp == null) {
//Must be an int,long,bigint
try {
return createInteger(val);
} catch (NumberFormatException nfe) {
// empty catch
}
try {
return createLong(val);
} catch (NumberFormatException nfe) {
// empty catch
}
return createBigInteger(val);
} else {
//Must be a float,double,BigDec
boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
try {
Float f = createFloat(val);
if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
return f;
}
} catch (NumberFormatException nfe) {
// empty catch
}
try {
Double d = createDouble(val);
if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {
return d;
}
} catch (NumberFormatException nfe) {
// empty catch
}
return createBigDecimal(val);
}
}
}
/**
* <p>Utility method for {@link #createNumber(java.lang.String)}.</p>
*
* <p>Returns <code>true</code> if s is <code>null</code>.</p>
*
* @param s the String to check
* @return if it is all zeros or <code>null</code>
*/
private static boolean isAllZeros(String s) {
if (s == null) {
return true;
}
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) != "0") {
return false;
}
}
return s.length() > 0;
}
//--------------------------------------------------------------------
/**
* <p>Convert a <code>String</code> to a <code>Float</code>.</p>
*
* @param val a <code>String</code> to convert
* @return converted <code>Float</code>
* @throws NumberFormatException if the value cannot be converted
*/
public static Float createFloat(String val) {
return Float.valueOf(val);
}
/**
* <p>Convert a <code>String</code> to a <code>Double</code>.</p>
*
* @param val a <code>String</code> to convert
* @return converted <code>Double</code>
* @throws NumberFormatException if the value cannot be converted
*/
public static Double createDouble(String val) {
return Double.valueOf(val);
}
/**
* <p>Convert a <code>String</code> to a <code>Integer</code>, handling
* hex and octal notations.</p>
*
* @param val a <code>String</code> to convert
* @return converted <code>Integer</code>
* @throws NumberFormatException if the value cannot be converted
*/
public static Integer createInteger(String val) {
// decode() handles 0xAABD and 0777 (hex and octal) as well.
return Integer.decode(val);
}
/**
* <p>Convert a <code>String</code> to a <code>Long</code>.</p>
*
* @param val a <code>String</code> to convert
* @return converted <code>Long</code>
* @throws NumberFormatException if the value cannot be converted
*/
public static Long createLong(String val) {
return Long.valueOf(val);
}
/**
* <p>Convert a <code>String</code> to a <code>BigInteger</code>.</p>
*
* @param val a <code>String</code> to convert
* @return converted <code>BigInteger</code>
* @throws NumberFormatException if the value cannot be converted
*/
public static BigInteger createBigInteger(String val) {
BigInteger bi = new BigInteger(val);
return bi;
}
/**
* <p>Convert a <code>String</code> to a <code>BigDecimal</code>.</p>
*
* @param val a <code>String</code> to convert
* @return converted <code>BigDecimal</code>
* @throws NumberFormatException if the value cannot be converted
*/
public static BigDecimal createBigDecimal(String val) {
BigDecimal bd = new BigDecimal(val);
return bd;
}
//--------------------------------------------------------------------
/**
* <p>Checks whether the <code>String</code> contains only
* digit characters.</p>
*
* <p><code>Null</code> and empty String will return
* <code>false</code>.</p>
*
* @param str the <code>String</code> to check
* @return <code>true</code> if str contains only unicode numeric
*/
public static boolean isDigits(String str) {
if ((str == null) || (str.length() == 0)) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
}
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Various number-related routines and classes that are frequently used.
*
* @author barclay
*/
public class Number {
/**
* Default number of decimal places to round to:
*/
public static final int DECIMAL_PLACES = 2;
/**
* Round a float to the default number of decimal places.
*
* @param value
* The value to round.
* @return The rounded value as a float.
* @see #DECIMAL_PLACES
*/
public static float Round(float value) {
return Round(value, DECIMAL_PLACES);
}
/**
* Round a float to the specified number of decimal places.
*
* @param value
* The value to round.
* @param places
* The number of decimal points.
* @return The rounded value as a float.
*/
public static float Round(float value, int places) {
float p = (float) Math.pow(10, places);
value = value * p;
float tmp = Math.round(value);
return (float) tmp / p;
}
/**
* Clamp a <code>value</code> to <code>min</code> or <code>max</code>,
* inclusive.
*
* @param value
* The value to clamp.
* @param min
* The minimum value.
* @param max
* The maximum value.
* @return If <code>value</code> is greater than <code>max</code> then
* <code>max</code>, else if <code>value</code> is less than
* <code>min</code> then <code>min</code>, else <code>value</code>.
*/
public static float Clamp(float value, float min, float max) {
if (value > max)
return max;
if (value < min)
return min;
return value;
}
public enum TrendState {
DOWN_15_GOOD,
DOWN_15_BAD,
DOWN_30_GOOD,
DOWN_30_BAD,
DOWN_45_GOOD,
DOWN_45_BAD,
UP_15_GOOD,
UP_15_BAD,
UP_30_GOOD,
UP_30_BAD,
UP_45_GOOD,
UP_45_BAD,
DOWN_15,
UP_15,
FLAT,
FLAT_GOAL,
UNKNOWN
};
public static TrendState getTrendState(float oldTrend, float newTrend,
float goal, float sensitivity, float stdDev) {
sensitivity = sensitivity * stdDev;
float half = sensitivity / 2.0f;
float quarter = sensitivity / 4.0f;
if (oldTrend == newTrend) {
// truly flat trend
if (newTrend == goal)
// perfect!
return TrendState.FLAT_GOAL;
else if (newTrend < goal && newTrend + quarter > goal)
// flat near the goal!
return TrendState.FLAT_GOAL;
else if (newTrend > goal && newTrend - quarter < goal)
// flat near the goal!
return TrendState.FLAT_GOAL;
else
return TrendState.FLAT;
} else if (oldTrend > newTrend) {
// going down
if (oldTrend > goal && newTrend > goal) {
// toward goal
if (oldTrend - newTrend > sensitivity)
// huge drop
return TrendState.DOWN_45_GOOD;
else if (oldTrend - newTrend > half)
// big drop
return TrendState.DOWN_30_GOOD;
else if (oldTrend - newTrend > quarter)
// little drop
return TrendState.DOWN_15_GOOD;
else {
// under bounds for flat
if (newTrend - quarter < goal)
// flat near the goal!
return TrendState.FLAT_GOAL;
else
// flat elsewhere
return TrendState.FLAT;
}
} else if (oldTrend < goal && newTrend < goal) {
// away from goal
if (oldTrend - newTrend > sensitivity)
// huge drop
return TrendState.DOWN_45_BAD;
else if (oldTrend - newTrend > half)
// big drop
return TrendState.DOWN_30_BAD;
else if (oldTrend - newTrend > quarter)
// little drop
return TrendState.DOWN_15_BAD;
else {
// under bounds for flat
if (newTrend + quarter > goal)
// flat near the goal!
return TrendState.FLAT_GOAL;
else
// flat elsewhere
return TrendState.FLAT;
}
} else
// crossing goal line
return TrendState.DOWN_15;
} else if (oldTrend < newTrend) {
// going up
if (oldTrend < goal && newTrend < goal) {
// toward goal
if (newTrend - oldTrend > sensitivity)
// big rise
return TrendState.UP_45_GOOD;
else if (newTrend - oldTrend > half)
// little rise
return TrendState.UP_30_GOOD;
else if (newTrend - oldTrend > quarter)
// little rise
return TrendState.UP_15_GOOD;
else {
// under bounds for flat
if (newTrend + quarter > goal)
// flat near the goal!
return TrendState.FLAT_GOAL;
else
// flat elsewhere
return TrendState.FLAT;
}
} else if (oldTrend > goal && newTrend > goal) {
// away from goal
if (newTrend - oldTrend > sensitivity)
// big rise
return TrendState.UP_45_BAD;
else if (newTrend - oldTrend > half)
// little rise
return TrendState.UP_30_BAD;
else if (newTrend - oldTrend > quarter)
// little rise
return TrendState.UP_15_BAD;
else {
// under bounds for flat
if (newTrend - quarter < goal)
// flat near the goal!
return TrendState.FLAT_GOAL;
else
// flat elsewhere
return TrendState.FLAT;
}
} else {
// crossing goal line
return TrendState.UP_15;
}
} else
// ??
return TrendState.UNKNOWN;
}
/**
* An exponentially smoothed weighted moving average. Not thread safe. Trend
* is calculated thusly: <br>
* <code>
* trend[n] := trend[n-1] + smoothing_percentage * (value[n] - value[n-1])
* </code>
*
* @author barclay
*/
public static class Trend {
/**
* Default smoothing percentage. This value will be used to scale the
* previous entry by multiplying the previous entry"s value and adding that
* to the current value, so a smoothing percentage of 0.1 is 10%.
*/
private static final float DEFAULT_SMOOTHING = 0.1f;
private int mNEntries = 0;
private float mSmoothing = DEFAULT_SMOOTHING;
private float mSum = 0.0f;
private boolean mFirst = true;
private float mTrendLast = 0.0f;
public float mTrendPrev = 0.0f;
public float mTrend = 0.0f;
public float mMin = 0.0f;
public float mMax = 0.0f;
public float mMean = 0.0f;
/**
* Default constructor. Set the smoothing percentage to the default.
*
* @see #DEFAULT_SMOOTHING
*/
public Trend() {
}
/**
* Constructor
*
* @param smoothing
* Sets the smoothing percentage to the specified value.
* @see #DEFAULT_SMOOTHING
*/
public Trend(float smoothing) {
mSmoothing = smoothing;
}
/**
* Copy Constructor
*
* @param source
* Returns a new instance of Trend with all data set to source.
* @see #DEFAULT_SMOOTHING
*/
public Trend(Trend source) {
mNEntries = source.mNEntries;
mSmoothing = source.mSmoothing;
mSum = source.mSum;
mFirst = source.mFirst;
mTrendLast = source.mTrendLast;
mTrendPrev = source.mTrendPrev;
mTrend = source.mTrend;
mMin = source.mMin;
mMax = source.mMax;
mMean = source.mMean;
}
/**
* Return the smoothing constant used by the Trend.
*
* @return The smoothing constant as a float.
*/
public float getSmoothing() {
return mSmoothing;
}
/**
* Update the trend with a new value. The value is implicitly "later" in the
* sequence than all previous values.
*
* @param val
* The value to add to the series.
*/
public void update(float val) {
mNEntries++;
mSum += val;
float oldMean = mMean;
mMean += (val - oldMean) / mNEntries;
// T(n) = T(n-1) + 0.1(V(n) - T(n-1))
// : T(n) is the trend number for day n
// : V(n) is the value number for day n
// : S is the smoothing factor (default 0.1)
if (mFirst == true) {
mFirst = false;
mTrend = val;
mMin = val;
mMax = val;
} else {
mTrend = mTrendLast + (mSmoothing * (val - mTrendLast));
if (mTrend < mMin)
mMin = mTrend;
if (mTrend > mMax)
mMax = mTrend;
}
mTrendPrev = mTrendLast;
mTrendLast = mTrend;
}
}
/**
* Class for keeping track of various statistics intended to be updated
* incrementally, including total number of updates, sum, mean, variance, and
* standard deviation of the series. Not thread safe.
*
* @author barclay
*/
public static class RunningStats {
public int mNDatapoints = 0;
public int mNEntries = 0;
public float mSum = 0.0f;
public float mMean = 0.0f;
public float mEntryMean = 0.0f;
public float mVarSum = 0.0f;
public float mVar = 0.0f;
public float mStdDev = 0.0f;
/**
* Sole constructor. Initializes all stats to 0.
*/
public RunningStats() {
}
/**
* Copy Constructor
*
* @param source
* Returns a new instance of RunningStats with all data set to
* source.
*/
public RunningStats(RunningStats source) {
mNDatapoints = source.mNDatapoints;
mNEntries = source.mNEntries;
mSum = source.mSum;
mMean = source.mMean;
mEntryMean = source.mEntryMean;
mVarSum = source.mVarSum;
mVar = source.mVar;
mStdDev = source.mStdDev;
}
/**
* update the statistics with the specified value. The value may be an
* aggregate of several other values, as indicated by the second parameter.
* A separate value will be recored for per-entry and and per-update means.
*
* @param val
* The value to update the statistics with.
* @param nEntries
* The number of entries this value is an aggregate of.
*/
public void update(float val, int nEntries) {
mNDatapoints++;
mNEntries += nEntries;
mSum += val;
// Mean is calculated thusly to avoid float expansion and contraction,
// which
// would minimize accuracy.
float oldMean = mMean;
mMean += (val - oldMean) / mNDatapoints;
mVarSum += (val - oldMean) * (val - mMean);
mVar = mVarSum / mNDatapoints;
mStdDev = (float) Math.sqrt(mVar);
if (mNEntries > 0) {
float oldEntryMean = mEntryMean;
mEntryMean += (val - oldEntryMean) / mNEntries;
}
return;
}
}
/**
* Class for keeping track of the Standard Deviation over the last X values.
*
* @author barclay
*/
public static class WindowedStdDev {
private Lock mLock;
private ArrayList<Float> mValues;
private int mHistory;
/**
* Sole constructor. Initializes all stats to 0.
*/
public WindowedStdDev(int history) {
mHistory = history;
mValues = new ArrayList<Float>(mHistory);
mLock = new ReentrantLock();
}
/**
* Copy Constructor
*
* @param source
* Returns a new instance of WindowedStdDev with all data set to
* source.
*/
public WindowedStdDev(WindowedStdDev source) {
mLock = new ReentrantLock();
source.waitForLock();
mHistory = source.mHistory;
mValues = new ArrayList<Float>(mHistory);
for (int i = 0; i < source.mValues.size(); i++) {
try {
mValues.add(new Float(source.mValues.get(i)));
} catch(IndexOutOfBoundsException e) {
break;
}
}
source.unlock();
}
public void waitForLock() {
while (lock() == false) {
}
}
public boolean lock() {
try {
return mLock.tryLock(250L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
public void unlock() {
mLock.unlock();
}
/**
* update the std dev with the specified value.
*
* @param val
* The value to update the statistics with.
*/
public void update(float val) {
waitForLock();
mValues.add(new Float(val));
if (mValues.size() > mHistory) {
try {
mValues.remove(0);
} catch(IndexOutOfBoundsException e) {
// nothing
}
}
unlock();
return;
}
/**
* Fetch current Standard Deviation.
*
* @param val
* The value to update the statistics with.
*/
public float getStandardDev() {
float mean = 0.0f;
float meanSqr = 0.0f;
float variance = 0.0f;
float delta = 0.0f;
float val = 0.0f;
waitForLock();
int nValues = mValues.size();
for (int i = 0; i < nValues; i++) {
try {
val = mValues.get(i);
delta = val - mean;
mean = mean + delta / (i + 1);
meanSqr = meanSqr + delta * (val - mean);
} catch(IndexOutOfBoundsException e) {
break;
}
}
unlock();
variance = meanSqr / nValues;
return (float) Math.sqrt(variance);
}
}
/**
* Performs a standard Pearson linear correlation on multiple series of data
* at one, returning the results in a matrix.
*
* @author barclay
*/
public static class LinearMatrixCorrelation {
private int mNumSeries = 0;
private int mNEntries = 0;
private Float[] mSum;
private Float[] mMean;
private Float[] mSumSquare;
private Float[] mStdDev;
private Float[][] mSumCoproduct;
private Float[][] mCovariance;
private Float[][] mCorrelation;
/**
* Constructor. Allocates internal data structures and zero"s out the output
* matrix data.
*
* @param numSeries
* The number of series that will be included in each call to
* <code>update()</code>.
*/
public LinearMatrixCorrelation(int numSeries) {
mNumSeries = numSeries;
mSum = new Float[numSeries];
mMean = new Float[numSeries];
mSumSquare = new Float[numSeries];
mStdDev = new Float[numSeries];
mSumCoproduct = new Float[numSeries][];
mCovariance = new Float[numSeries][];
mCorrelation = new Float[numSeries][];
for (int i = 0; i < numSeries; i++) {
mSum[i] = 0.0f;
mMean[i] = 0.0f;
mSumSquare[i] = 0.0f;
mStdDev[i] = 0.0f;
mSumCoproduct[i] = new Float[numSeries];
mCovariance[i] = new Float[numSeries];
mCorrelation[i] = new Float[numSeries];
for (int j = 0; j < numSeries; j++) {
mSumCoproduct[i][j] = 0.0f;
mCovariance[i][j] = 0.0f;
mCorrelation[i][j] = 0.0f;
}
}
}
/**
* Adds a vector (array) of values, 1 per series, to the calculations.
* Graphically, all values are considered to be the at the same X (or Y)
* position, and the values in the array argument denote the corresponding Y
* (or X) value specific to the each series. Thus, the parameter x is an
* array of values x[0 .. numSeries-1], one value per series, all of which
* occured at the same "time." If a series has no such value, the entry in
* the array should be null, as the length of the array must match the
* <code>numSeries</code> past into the constructor at each invocation.
*
* @param x
* The values for each series as Floats.
* @return true if the input acceptable, else false if the length of
* <code>x[]</code> does not match <code>numSeries</code> or a value
* less than 1 was passed to the constructor.
* @see LinearMatrixCorrelation#LinearMatrixCorrelation
*/
public boolean update(Float[] x) {
float oldMean;
if (x.length != mNumSeries)
return false;
if (mNEntries + 1 > mNumSeries)
return false;
mNEntries++;
float sweep = (mNEntries - 1.0f) / mNEntries;
for (int i = 0; i < x.length; i++) {
if (x[i] != null) {
mSum[i] += x[i];
oldMean = mMean[i];
mMean[i] += (x[i] - oldMean) / mNEntries;
mSumSquare[i] += (x[i] - oldMean) * (x[i] - mMean[i]);
mStdDev[i] = (float) Math.sqrt(mSumSquare[i] * sweep);
}
}
for (int i = 0; i < x.length; i++) {
if (x[i] != null) {
for (int j = i + 1; j < x.length; j++) {
if (x[j] != null) {
mSumCoproduct[i][j] += (x[i] - mMean[i]) * (x[j] - mMean[j]);
mCovariance[i][j] = mSumCoproduct[i][j] * sweep;
mCorrelation[i][j] = mCovariance[i][j]
/ (mStdDev[i] * mStdDev[j]);
mCorrelation[j][i] = mCovariance[i][j]
/ (mStdDev[i] * mStdDev[j]);
mCorrelation[i][j] = mCovariance[i][j]
/ (mStdDev[i] * mStdDev[j]);
}
}
}
mCorrelation[i][i] = 1.0f;
}
return true;
}
/**
* Returns a reference to the correlation output matrix. The upper right
* triangle is a mirror of the lower left, and the dividing diagonal the
* identity correlation, i.e., 1.0f. In order to run through the matrix
* without duplicates (e.g., processing both output[i][j] and output[j][i],
* use a construct like: <br>
*
* <pre>
* for (int i = 0; i < output.length; i++) {
* for (int j = i+1; j < output.length; j++) {
* if (output[i][j] != null) { ... }
* }
* }
* </pre>
*
* Note that any correlations that could not be calculated, either due to
* lack of datapoints or structure of the data, will be null.
*
* @return Float[][], the output correlation matrix.
*/
public Float[][] getCorrelations() {
return mCorrelation;
}
/**
* Return a string interpretation of the linear correlation value. Note that
* this is highly dependent on the data being correlated, and should be no
* means be taken as gospel.
*
* @param c
* The correlation value, should be -1.0f <= c <= 1.0f.
* @return A string interpretation.
*/
public static String correlationToString(float c) {
if (c > 0.5)
return "Strong";
if (c < -0.5)
return "Inverse Strong";
if (c > 0.3)
return "Medium";
if (c < -0.3)
return "Inverse Medium";
return "Weak";
}
}
}