Java/Data Type/Number
Содержание
- 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
<source lang="java">
/*
* 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); }
}
</source>
Check Number properties and convert from Number
<source lang="java">
/**
* 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 differentjava.lang.Number
* 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.,Byte, Short, Integer, Long, * Float, Double, BigInteger, BigDecimal
). * * @author Oliver Stuhr */
public class NumberUtils {
/** * Answerstrue
iff the given number is an instance of *java.math.BigDecimal
orjava.math.BigInteger
. * * @param number * @return boolean */ public static boolean isBig(Number number) { return number instanceof BigDecimal || number instanceof BigInteger; } /** * Answerstrue
iff the given number is an instance of *Byte
,Short
,Integer
orLong
. * * @param number * @return boolean */ public static boolean isLongCompatible(Number number) { return number instanceof Byte || number instanceof Short || number instanceof Integer || number instanceof Long; } /** * Answerstrue
iff the given number is an instance of *Float
orDouble
. * * @param number * @return boolean */ public static boolean isDoubleCompatible(Number number) { return number instanceof Float || number instanceof Double; } /** * Answerstrue
iff the given number is infinite (i.e., is * aFloat
orDouble
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; } /** * Answerstrue
iff the given number is "not a number" * (i.e., is aFloat
orDouble
containing * one of the predefined constant values representingNaN
). * * @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.,-1
if it is negative,0
* if it is zero and1
if it is positive). * * @param number * @return int * @throws ArithmeticException The given number isnull
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 aByte
(by usingbyteValue()
). * * @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 aShort
(by usingshortValue()
). * * @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 aInteger
(by usingintValue()
). * * @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 aLong
(by usinglongValue()
). * * @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 aFloat
(by usingfloatValue()
). * * @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 aDouble
(by usingdoubleValue()
). * * @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 ajava.math.BigInteger
. * * @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 ajava.math.BigDecimal
. * * @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 isnull
or "not a number", * throw an exception. * 2. If both values are "long compatible", compare theirlongValue()
* using the usual comparison operators for primitive types (<, ==, >). * 3. If both values are "double compatible", compare theirdoubleValue()
* 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 tojava.math.BigDecimal
and * return the result of theBigDecimal.rupareTo(BigDecimal)
method. * * As a consequence, the method is not suitable to implement a *java.util.ruparator
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, asDouble.rupare(double, double)
* 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 *compareTo(...)
methods. Besides the handling of * "not a number" values this makes a difference, when comparing * the float or double values-0.0
and0.0
: * again, like the operators, we consider them as equal (whereas * according toDouble.rupareTo(...)
-0.0
* is less than0.0
). * * @param first * @param second * @return int * @throws ArithmeticException One or both of the given numbers isnull
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)); }
}
</source>
Checks whether the String a valid Java number.
<source lang="java">
/*
* 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 //----------------------------------------------------------------------- /***
Checks if a String is empty ("") or null.
**
* StringUtils.isEmpty(null) = true * StringUtils.isEmpty("") = true * StringUtils.isEmpty(" ") = false * StringUtils.isEmpty("bob") = false * StringUtils.isEmpty(" bob ") = false *
**
NOTE: This method changed in Lang version 2.0. * It no longer trims the String. * That functionality is available in isBlank().
*
* @param str the String to check, may be null
* @return true
if the String is empty or null
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
/**
* Checks whether the String a valid Java number.
**
Valid numbers include hexadecimal marked with the 0x
* qualifier, scientific notation and numbers marked with a type
* qualifier (e.g. 123L).
**
Null
and empty String will return
* false
.
* * @param str theString
to check * @returntrue
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; }
}
</source>
Convert to numbers
<source lang="java">
/*
* 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(); } } </source>
Get Digit Number String
<source lang="java">
/*
* 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(); }
}
</source>
Methods for number conversion and parsing
<source lang="java">
/*
* 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 defaultdecode
methods. Trims the * inputString
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 inputString
* 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 (ifnull
, * this method falls back toparseNumber(String, Class)
) * @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); }
}
</source>
Provides IEEE-754r variants of NumberUtils methods.
<source lang="java">
/*
* 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. */
/**
*Provides IEEE-754r variants of NumberUtils methods.
**
See:
* * @since 2.4 * @version $Id: IEEE754rUtils.java 634088 2008-03-06 00:06:05Z niallp $ */
public class IEEE754rUtils {
/***
Returns the minimum value in an array.
* * @param array an array, must not be null or empty * @return the minimum value in the array * @throws IllegalArgumentException if*array
isnull
* @throws IllegalArgumentException ifarray
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; } /**
Returns the minimum value in an array.
* * @param array an array, must not be null or empty * @return the minimum value in the array * @throws IllegalArgumentException if*array
isnull
* @throws IllegalArgumentException ifarray
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; } /**
Gets the minimum of three double
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } /***
Gets the minimum of two double
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } } /***
Gets the minimum of three float
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } /***
Gets the minimum of two float
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } } /***
Returns the maximum value in an array.
* * @param array an array, must not be null or empty * @return the minimum value in the array * @throws IllegalArgumentException if*array
isnull
* @throws IllegalArgumentException ifarray
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; } /**
Returns the maximum value in an array.
* * @param array an array, must not be null or empty * @return the minimum value in the array * @throws IllegalArgumentException if*array
isnull
* @throws IllegalArgumentException ifarray
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; } /**
Gets the maximum of three double
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } /***
Gets the maximum of two double
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } } /***
Gets the maximum of three float
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } /***
Gets the maximum of two float
values.
**
NaN is only returned if all numbers are NaN as per IEEE-754r.
* * @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); } }
}
</source>
Turns a string value into a java.lang.Number.
<source lang="java">
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. /***
Turns a string value into a java.lang.Number.
**
First, the value is examined for a type qualifier on the end
* ("f","F","d","D","l","L"
). 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.
**
If a type specifier is not found, it will check for a decimal point
* and then try successively larger types from Integer
to
* BigInteger
and from Float
to
* BigDecimal
.
**
If the string starts with 0x
or -0x
, it
* will be interpreted as a hexadecimal integer. Values with leading
* 0
"s will not be interpreted as octal.
* * @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); } } } /***
Utility method for {@link #createNumber(java.lang.String)}.
**
Returns true
if s is null
.
*
* @param s the String to check
* @return if it is all zeros or null
*/
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;
}
//--------------------------------------------------------------------
/**
* Convert a String
to a Float
.
* * @param val a*String
to convert * @return convertedFloat
* @throws NumberFormatException if the value cannot be converted */ public static Float createFloat(String val) { return Float.valueOf(val); } /**
Convert a String
to a Double
.
* * @param val a*String
to convert * @return convertedDouble
* @throws NumberFormatException if the value cannot be converted */ public static Double createDouble(String val) { return Double.valueOf(val); } /**
Convert a String
to a Integer
, handling
* hex and octal notations.
* * @param val a*String
to convert * @return convertedInteger
* @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); } /**
Convert a String
to a Long
.
* * @param val a*String
to convert * @return convertedLong
* @throws NumberFormatException if the value cannot be converted */ public static Long createLong(String val) { return Long.valueOf(val); } /**
Convert a String
to a BigInteger
.
* * @param val a*String
to convert * @return convertedBigInteger
* @throws NumberFormatException if the value cannot be converted */ public static BigInteger createBigInteger(String val) { BigInteger bi = new BigInteger(val); return bi; } /**
Convert a String
to a BigDecimal
.
* * @param val a*String
to convert * @return convertedBigDecimal
* @throws NumberFormatException if the value cannot be converted */ public static BigDecimal createBigDecimal(String val) { BigDecimal bd = new BigDecimal(val); return bd; } //-------------------------------------------------------------------- /**
Checks whether the String
contains only
* digit characters.
**
Null
and empty String will return
* false
.
* * @param str theString
to check * @returntrue
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; }
}
</source>
<source lang="java">
/*
* 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*value
tomin
ormax
, * inclusive. * * @param value * The value to clamp. * @param min * The minimum value. * @param max * The maximum value. * @return Ifvalue
is greater thanmax
then *max
, else ifvalue
is less than *min
thenmin
, elsevalue
. */ 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:
** trend[n] := trend[n-1] + smoothing_percentage * (value[n] - value[n-1]) *
* * @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 *update()
. */ 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 *numSeries
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 *x[]
does not matchnumSeries
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:
*
* for (int i = 0; i < output.length; i++) { * for (int j = i+1; j < output.length; j++) { * if (output[i][j] != null) { ... } * } * } *
* * 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"; } }
}
</source>