Java Tutorial/Data Type/Number

Материал из Java эксперт
Перейти к: навигация, поиск

An integer synchronized counter class.

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.util;
import java.io.Serializable;
/**
 * An integer counter class.
 *
 * @version <tt>$Revision: 2800 $</tt>
 * @author  
 */
public class Counter
   implements Serializable, Cloneable
{
   /** The serialVersionUID */
   private static final long serialVersionUID = 7736259185393081556L;
   /** The current count */
   private int count;
   /**
    * Construct a Counter with a starting value.
    *
    * @param count   Starting value for counter.
    */
   public Counter(final int count) {
      this.count = count;
   }
   /**
    * Construct a Counter.
    */
   public Counter() {}
   /**
    * Increment the counter. (Optional operation)
    *
    * @return  The incremented value of the counter.
    */
   public int increment() {
      return ++count;
   }
   /**
    * Decrement the counter. (Optional operation)
    *
    * @return  The decremented value of the counter.
    */
   public int decrement() {
      return --count;
   }
   /**
    * Return the current value of the counter.
    *
    * @return  The current value of the counter.
    */
   public int getCount() {
      return count;
   }
   /**
    * Reset the counter to zero. (Optional operation)
    */
   public void reset() {
      this.count = 0;
   }
   /**
    * Check if the given object is equal to this.
    *
    * @param obj  Object to test equality with.
    * @return     True if object is equal to this.
    */
   public boolean equals(final Object obj) {
      if (obj == this) return true;
      if (obj != null && obj.getClass() == getClass()) {
         return ((Counter)obj).count == count;
      }
      
      return false;
   }
   /**
    * Return a string representation of this.
    *
    * @return  A string representation of this.
    */
   public String toString() {
      return String.valueOf(count);
   }
   /**
    * Return a cloned copy of this object.
    *
    * @return  A cloned copy of this object.
    */
   public Object clone() {
      try {
         return super.clone();
      }
      catch (CloneNotSupportedException e) {
         throw new InternalError();
      }
   }

   /////////////////////////////////////////////////////////////////////////
   //                                Wrappers                             //
   /////////////////////////////////////////////////////////////////////////
   /**
    * Base wrapper class for other wrappers.
    */
   private static class Wrapper
      extends Counter
   {
      /** The serialVersionUID */
      private static final long serialVersionUID = -1803971437884946242L;
      /** The wrapped counter */
      protected final Counter counter;
      public Wrapper(final Counter counter) {
         this.counter = counter;
      }
      public int increment() {
         return counter.increment();
      }
      public int decrement() {
         return counter.decrement();
      }
      public int getCount() {
         return counter.getCount();
      }
      public void reset() {
         counter.reset();
      }
      public boolean equals(final Object obj) {
         return counter.equals(obj);
      }
      public String toString() {
         return counter.toString();
      }
      public Object clone() {
         return counter.clone();
      }
   }
   /**
    * Return a synchronized counter.
    *
    * @param counter    Counter to synchronize.
    * @return           Synchronized counter.
    */
   public static Counter makeSynchronized(final Counter counter) {
      return new Wrapper(counter) {
            /** The serialVersionUID */
         private static final long serialVersionUID = -6024309396861726945L;
            public synchronized int increment() {
               return this.counter.increment();
            }
            public synchronized int decrement() {
               return this.counter.decrement();
            }
            public synchronized int getCount() {
               return this.counter.getCount();
            }
            public synchronized void reset() {
               this.counter.reset();
            }
            public synchronized int hashCode() {
               return this.counter.hashCode();
            }
            public synchronized boolean equals(final Object obj) {
               return this.counter.equals(obj);
            }
            public synchronized String toString() {
               return this.counter.toString();
            }
            public synchronized Object clone() {
               return this.counter.clone();
            }
         };
   }
   /**
    * Returns a directional counter.
    *
    * @param counter       Counter to make directional.
    * @param increasing    True to create an increasing only
    *                      or false to create a decreasing only.
    * @return              A directional counter.
    */
   public static Counter makeDirectional(final Counter counter,
                                         final boolean increasing)
   {
      Counter temp;
      if (increasing) {
         temp = new Wrapper(counter) {
               /** The serialVersionUID */
            private static final long serialVersionUID = 2161377898611431781L;
               public int decrement() {
                  throw new UnsupportedOperationException();
               }
               public void reset() {
                  throw new UnsupportedOperationException();
               }
            };
      }
      else {
         temp = new Wrapper(counter) {
            /** The serialVersionUID */
            private static final long serialVersionUID = -4683457706354663230L;
               public int increment() {
                  throw new UnsupportedOperationException();
               }
            };
      }
      
      return temp;
   }
}





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 (&lt;, ==, &gt;).
   * 3. If both values are "double compatible", compare their <code>doubleValue()</code>
   *    using the usual comparison operators for primitive types (&lt;, ==, &gt;).
   * 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));
  }
}





Fraction is a Number implementation that stores fractions accurately.

/*
 * 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.
 */
// Revised from commons math from Apache
import java.math.BigInteger;
/**
 * <p><code>Fraction</code> is a <code>Number</code> implementation that
 * stores fractions accurately.</p>
 *
 * <p>This class is immutable, and interoperable with most methods that accept
 * a <code>Number</code>.</p>
 *
 * @author Travis Reeder
 * @author Stephen Colebourne
 * @author Tim O"Brien
 * @author Pete Gieser
 * @author C. Scott Ananian
 * @since 2.0
 * @version $Id: Fraction.java 599500 2007-11-29 16:25:54Z mbenson $
 */
public final class Fraction extends Number implements Comparable {
    /**
     * Required for serialization support. Lang version 2.0.
     * 
     * @see java.io.Serializable
     */
    private static final long serialVersionUID = 65382027393090L;
    /**
     * <code>Fraction</code> representation of 0.
     */
    public static final Fraction ZERO = new Fraction(0, 1);
    /**
     * <code>Fraction</code> representation of 1.
     */
    public static final Fraction ONE = new Fraction(1, 1);
    /**
     * <code>Fraction</code> representation of 1/2.
     */
    public static final Fraction ONE_HALF = new Fraction(1, 2);
    /**
     * <code>Fraction</code> representation of 1/3.
     */
    public static final Fraction ONE_THIRD = new Fraction(1, 3);
    /**
     * <code>Fraction</code> representation of 2/3.
     */
    public static final Fraction TWO_THIRDS = new Fraction(2, 3);
    /**
     * <code>Fraction</code> representation of 1/4.
     */
    public static final Fraction ONE_QUARTER = new Fraction(1, 4);
    /**
     * <code>Fraction</code> representation of 2/4.
     */
    public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
    /**
     * <code>Fraction</code> representation of 3/4.
     */
    public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
    /**
     * <code>Fraction</code> representation of 1/5.
     */
    public static final Fraction ONE_FIFTH = new Fraction(1, 5);
    /**
     * <code>Fraction</code> representation of 2/5.
     */
    public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
    /**
     * <code>Fraction</code> representation of 3/5.
     */
    public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
    /**
     * <code>Fraction</code> representation of 4/5.
     */
    public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);

    /**
     * The numerator number part of the fraction (the three in three sevenths).
     */
    private final int numerator;
    /**
     * The denominator number part of the fraction (the seven in three sevenths).
     */
    private final int denominator;
    /**
     * Cached output hashCode (class is immutable).
     */
    private transient int hashCode = 0;
    /**
     * Cached output toString (class is immutable).
     */
    private transient String toString = null;
    /**
     * Cached output toProperString (class is immutable).
     */
    private transient String toProperString = null;
    /**
     * <p>Constructs a <code>Fraction</code> instance with the 2 parts
     * of a fraction Y/Z.</p>
     *
     * @param numerator  the numerator, for example the three in "three sevenths"
     * @param denominator  the denominator, for example the seven in "three sevenths"
     */
    private Fraction(int numerator, int denominator) {
        super();
        this.numerator = numerator;
        this.denominator = denominator;
    }
    /**
     * <p>Creates a <code>Fraction</code> instance with the 2 parts
     * of a fraction Y/Z.</p>
     *
     * <p>Any negative signs are resolved to be on the numerator.</p>
     *
     * @param numerator  the numerator, for example the three in "three sevenths"
     * @param denominator  the denominator, for example the seven in "three sevenths"
     * @return a new fraction instance
     * @throws ArithmeticException if the denomiator is <code>zero</code>
     */
    public static Fraction getFraction(int numerator, int denominator) {
        if (denominator == 0) {
            throw new ArithmeticException("The denominator must not be zero");
        }
        if (denominator < 0) {
            if (numerator==Integer.MIN_VALUE ||
                    denominator==Integer.MIN_VALUE) {
                throw new ArithmeticException("overflow: can"t negate");
            }
            numerator = -numerator;
            denominator = -denominator;
        }
        return new Fraction(numerator, denominator);
    }
    /**
     * <p>Creates a <code>Fraction</code> instance with the 3 parts
     * of a fraction X Y/Z.</p>
     *
     * <p>The negative sign must be passed in on the whole number part.</p>
     *
     * @param whole  the whole number, for example the one in "one and three sevenths"
     * @param numerator  the numerator, for example the three in "one and three sevenths"
     * @param denominator  the denominator, for example the seven in "one and three sevenths"
     * @return a new fraction instance
     * @throws ArithmeticException if the denomiator is <code>zero</code>
     * @throws ArithmeticException if the denominator is negative
     * @throws ArithmeticException if the numerator is negative
     * @throws ArithmeticException if the resulting numerator exceeds 
     *  <code>Integer.MAX_VALUE</code>
     */
    public static Fraction getFraction(int whole, int numerator, int denominator) {
        if (denominator == 0) {
            throw new ArithmeticException("The denominator must not be zero");
        }
        if (denominator < 0) {
            throw new ArithmeticException("The denominator must not be negative");
        }
        if (numerator < 0) {
            throw new ArithmeticException("The numerator must not be negative");
        }
        long numeratorValue;
        if (whole < 0) {
            numeratorValue = whole * (long)denominator - numerator;
        } else {
            numeratorValue = whole * (long)denominator + numerator;
        }
        if (numeratorValue < Integer.MIN_VALUE ||
                numeratorValue > Integer.MAX_VALUE)  {
            throw new ArithmeticException("Numerator too large to represent as an Integer.");
        }
        return new Fraction((int) numeratorValue, denominator);
    }
    /**
     * <p>Creates a reduced <code>Fraction</code> instance with the 2 parts
     * of a fraction Y/Z.</p>
     *
     * <p>For example, if the input parameters represent 2/4, then the created
     * fraction will be 1/2.</p>
     *
     * <p>Any negative signs are resolved to be on the numerator.</p>
     *
     * @param numerator  the numerator, for example the three in "three sevenths"
     * @param denominator  the denominator, for example the seven in "three sevenths"
     * @return a new fraction instance, with the numerator and denominator reduced
     * @throws ArithmeticException if the denominator is <code>zero</code>
     */
    public static Fraction getReducedFraction(int numerator, int denominator) {
        if (denominator == 0) {
            throw new ArithmeticException("The denominator must not be zero");
        }
        if (numerator==0) {
            return ZERO; // normalize zero.
        }
        // allow 2^k/-2^31 as a valid fraction (where k>0)
        if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
            numerator/=2; denominator/=2;
        }
        if (denominator < 0) {
            if (numerator==Integer.MIN_VALUE ||
                    denominator==Integer.MIN_VALUE) {
                throw new ArithmeticException("overflow: can"t negate");
            }
            numerator = -numerator;
            denominator = -denominator;
        }
        // simplify fraction.
        int gcd = greatestCommonDivisor(numerator, denominator);
        numerator /= gcd;
        denominator /= gcd;
        return new Fraction(numerator, denominator);
    }
    /**
     * <p>Creates a <code>Fraction</code> instance from a <code>double</code> value.</p>
     *
     * <p>This method uses the , computing a maximum of
     *  25 convergents and bounding the denominator by 10,000.</p>
     *
     * @param value  the double value to convert
     * @return a new fraction instance that is close to the value
     * @throws ArithmeticException if <code>|value| > Integer.MAX_VALUE</code> 
     *  or <code>value = NaN</code>
     * @throws ArithmeticException if the calculated denominator is <code>zero</code>
     * @throws ArithmeticException if the the algorithm does not converge
     */
    public static Fraction getFraction(double value) {
        int sign = (value < 0 ? -1 : 1);
        value = Math.abs(value);
        if (value  > Integer.MAX_VALUE || Double.isNaN(value)) {
            throw new ArithmeticException
                ("The value must not be greater than Integer.MAX_VALUE or NaN");
        }
        int wholeNumber = (int) value;
        value -= wholeNumber;
        
        int numer0 = 0;  // the pre-previous
        int denom0 = 1;  // the pre-previous
        int numer1 = 1;  // the previous
        int denom1 = 0;  // the previous
        int numer2 = 0;  // the current, setup in calculation
        int denom2 = 0;  // the current, setup in calculation
        int a1 = (int) value;
        int a2 = 0;
        double x1 = 1;
        double x2 = 0;
        double y1 = value - a1;
        double y2 = 0;
        double delta1, delta2 = Double.MAX_VALUE;
        double fraction;
        int i = 1;
//        System.out.println("---");
        do {
            delta1 = delta2;
            a2 = (int) (x1 / y1);
            x2 = y1;
            y2 = x1 - a2 * y1;
            numer2 = a1 * numer1 + numer0;
            denom2 = a1 * denom1 + denom0;
            fraction = (double) numer2 / (double) denom2;
            delta2 = Math.abs(value - fraction);
//            System.out.println(numer2 + " " + denom2 + " " + fraction + " " + delta2 + " " + y1);
            a1 = a2;
            x1 = x2;
            y1 = y2;
            numer0 = numer1;
            denom0 = denom1;
            numer1 = numer2;
            denom1 = denom2;
            i++;
//            System.out.println(">>" + delta1 +" "+ delta2+" "+(delta1 > delta2)+" "+i+" "+denom2);
        } while ((delta1 > delta2) && (denom2 <= 10000) && (denom2 > 0) && (i < 25));
        if (i == 25) {
            throw new ArithmeticException("Unable to convert double to fraction");
        }
        return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
    }
    /**
     * <p>Creates a Fraction from a <code>String</code>.</p>
     *
     * <p>The formats accepted are:</p>
     *
     * <ol>
     *  <li><code>double</code> String containing a dot</li>
     *  <li>"X Y/Z"</li>
     *  <li>"Y/Z"</li>
     *  <li>"X" (a simple whole number)</li>
     * </ol>
     * and a .</p>
     *
     * @param str  the string to parse, must not be <code>null</code>
     * @return the new <code>Fraction</code> instance
     * @throws IllegalArgumentException if the string is <code>null</code>
     * @throws NumberFormatException if the number format is invalid
     */
    public static Fraction getFraction(String str) {
        if (str == null) {
            throw new IllegalArgumentException("The string must not be null");
        }
        // parse double format
        int pos = str.indexOf(".");
        if (pos >= 0) {
            return getFraction(Double.parseDouble(str));
        }
        // parse X Y/Z format
        pos = str.indexOf(" ");
        if (pos > 0) {
            int whole = Integer.parseInt(str.substring(0, pos));
            str = str.substring(pos + 1);
            pos = str.indexOf("/");
            if (pos < 0) {
                throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
            } else {
                int numer = Integer.parseInt(str.substring(0, pos));
                int denom = Integer.parseInt(str.substring(pos + 1));
                return getFraction(whole, numer, denom);
            }
        }
        // parse Y/Z format
        pos = str.indexOf("/");
        if (pos < 0) {
            // simple whole number
            return getFraction(Integer.parseInt(str), 1);
        } else {
            int numer = Integer.parseInt(str.substring(0, pos));
            int denom = Integer.parseInt(str.substring(pos + 1));
            return getFraction(numer, denom);
        }
    }
    // Accessors
    //-------------------------------------------------------------------
    /**
     * <p>Gets the numerator part of the fraction.</p>
     *
     * <p>This method may return a value greater than the denominator, an
     * improper fraction, such as the seven in 7/4.</p>
     *
     * @return the numerator fraction part
     */
    public int getNumerator() {
        return numerator;
    }
    /**
     * <p>Gets the denominator part of the fraction.</p>
     *
     * @return the denominator fraction part
     */
    public int getDenominator() {
        return denominator;
    }
    /**
     * <p>Gets the proper numerator, always positive.</p>
     *
     * <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
     * This method returns the 3 from the proper fraction.</p>
     *
     * <p>If the fraction is negative such as -7/4, it can be resolved into
     * -1 3/4, so this method returns the positive proper numerator, 3.</p>
     *
     * @return the numerator fraction part of a proper fraction, always positive
     */
    public int getProperNumerator() {
        return Math.abs(numerator % denominator);
    }
    /**
     * <p>Gets the proper whole part of the fraction.</p>
     *
     * <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
     * This method returns the 1 from the proper fraction.</p>
     *
     * <p>If the fraction is negative such as -7/4, it can be resolved into
     * -1 3/4, so this method returns the positive whole part -1.</p>
     *
     * @return the whole fraction part of a proper fraction, that includes the sign
     */
    public int getProperWhole() {
        return numerator / denominator;
    }
    // Number methods
    //-------------------------------------------------------------------
    /**
     * <p>Gets the fraction as an <code>int</code>. This returns the whole number
     * part of the fraction.</p>
     *
     * @return the whole number fraction part
     */
    public int intValue() {
        return numerator / denominator;
    }
    /**
     * <p>Gets the fraction as a <code>long</code>. This returns the whole number
     * part of the fraction.</p>
     *
     * @return the whole number fraction part
     */
    public long longValue() {
        return (long) numerator / denominator;
    }
    /**
     * <p>Gets the fraction as a <code>float</code>. This calculates the fraction
     * as the numerator divided by denominator.</p>
     *
     * @return the fraction as a <code>float</code>
     */
    public float floatValue() {
        return ((float) numerator) / ((float) denominator);
    }
    /**
     * <p>Gets the fraction as a <code>double</code>. This calculates the fraction
     * as the numerator divided by denominator.</p>
     *
     * @return the fraction as a <code>double</code>
     */
    public double doubleValue() {
        return ((double) numerator) / ((double) denominator);
    }
    // Calculations
    //-------------------------------------------------------------------
    /**
     * <p>Reduce the fraction to the smallest values for the numerator and
     * denominator, returning the result.</p>
     * 
     * <p>For example, if this fraction represents 2/4, then the result
     * will be 1/2.</p>
     *
     * @return a new reduced fraction instance, or this if no simplification possible
     */
    public Fraction reduce() {
        if (numerator == 0) {
            return equals(ZERO) ? this : ZERO;
        }
        int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
        if (gcd == 1) {
            return this;
        }
        return Fraction.getFraction(numerator / gcd, denominator / gcd);
    }
    /**
     * <p>Gets a fraction that is the inverse (1/fraction) of this one.</p>
     * 
     * <p>The returned fraction is not reduced.</p>
     *
     * @return a new fraction instance with the numerator and denominator
     *         inverted.
     * @throws ArithmeticException if the fraction represents zero.
     */
    public Fraction invert() {
        if (numerator == 0) {
            throw new ArithmeticException("Unable to invert zero.");
        }
        if (numerator==Integer.MIN_VALUE) {
            throw new ArithmeticException("overflow: can"t negate numerator");
        }
        if (numerator<0) {
            return new Fraction(-denominator, -numerator);
        } else {
            return new Fraction(denominator, numerator);
        }
    }
    /**
     * <p>Gets a fraction that is the negative (-fraction) of this one.</p>
     *
     * <p>The returned fraction is not reduced.</p>
     *
     * @return a new fraction instance with the opposite signed numerator
     */
    public Fraction negate() {
        // the positive range is one smaller than the negative range of an int.
        if (numerator==Integer.MIN_VALUE) {
            throw new ArithmeticException("overflow: too large to negate");
        }
        return new Fraction(-numerator, denominator);
    }
    /**
     * <p>Gets a fraction that is the positive equivalent of this one.</p>
     * <p>More precisely: <code>(fraction >= 0 ? this : -fraction)</code></p>
     *
     * <p>The returned fraction is not reduced.</p>
     *
     * @return <code>this</code> if it is positive, or a new positive fraction
     *  instance with the opposite signed numerator
     */
    public Fraction abs() {
        if (numerator >= 0) {
            return this;
        }
        return negate();
    }
    /**
     * <p>Gets a fraction that is raised to the passed in power.</p>
     *
     * <p>The returned fraction is in reduced form.</p>
     *
     * @param power  the power to raise the fraction to
     * @return <code>this</code> if the power is one, <code>ONE</code> if the power
     * is zero (even if the fraction equals ZERO) or a new fraction instance 
     * raised to the appropriate power
     * @throws ArithmeticException if the resulting numerator or denominator exceeds
     *  <code>Integer.MAX_VALUE</code>
     */
    public Fraction pow(int power) {
        if (power == 1) {
            return this;
        } else if (power == 0) {
            return ONE;
        } else if (power < 0) {
            if (power==Integer.MIN_VALUE) { // MIN_VALUE can"t be negated.
                return this.invert().pow(2).pow(-(power/2));
            }
            return this.invert().pow(-power);
        } else {
            Fraction f = this.multiplyBy(this);
            if ((power % 2) == 0) { // if even...
                return f.pow(power/2);
            } else { // if odd...
                return f.pow(power/2).multiplyBy(this);
            }
        }
    }
    /**
     * <p>Gets the greatest common divisor of the absolute value of
     * two numbers, using the "binary gcd" method which avoids
     * division and modulo operations.  See Knuth 4.5.2 algorithm B.
     * This algorithm is due to Josef Stein (1961).</p>
     *
     * @param u  a non-zero number
     * @param v  a non-zero number
     * @return the greatest common divisor, never zero
     */
    private static int greatestCommonDivisor(int u, int v) {
        //if either op. is abs 0 or 1, return 1:
        if (Math.abs(u) <= 1 || Math.abs(v) <= 1) {
            return 1;
        }
        // keep u and v negative, as negative integers range down to
        // -2^31, while positive numbers can only be as large as 2^31-1
        // (i.e. we can"t necessarily negate a negative number without
        // overflow)
        if (u>0) { u=-u; } // make u negative
        if (v>0) { v=-v; } // make v negative
        // B1. [Find power of 2]
        int k=0;
        while ((u&1)==0 && (v&1)==0 && k<31) { // while u and v are both even...
            u/=2; v/=2; k++; // cast out twos.
        }
        if (k==31) {
            throw new ArithmeticException("overflow: gcd is 2^31");
        }
        // B2. Initialize: u and v have been divided by 2^k and at least
        //     one is odd.
        int t = ((u&1)==1) ? v : -(u/2)/*B3*/;
        // t negative: u was odd, v may be even (t replaces v)
        // t positive: u was even, v is odd (t replaces u)
        do {
            /* assert u<0 && v<0; */
            // B4/B3: cast out twos from t.
            while ((t&1)==0) { // while t is even..
                t/=2; // cast out twos
            }
            // B5 [reset max(u,v)]
            if (t>0) {
                u = -t;
            } else {
                v = t;
            }
            // B6/B3. at this point both u and v should be odd.
            t = (v - u)/2;
            // |u| larger: t positive (replace u)
            // |v| larger: t negative (replace v)
        } while (t!=0);
        return -u*(1<<k); // gcd is u*2^k
    }
    // Arithmetic
    //-------------------------------------------------------------------
    /** 
     * Multiply two integers, checking for overflow.
     * 
     * @param x a factor
     * @param y a factor
     * @return the product <code>x*y</code>
     * @throws ArithmeticException if the result can not be represented as
     *                             an int
     */
    private static int mulAndCheck(int x, int y) {
        long m = ((long)x)*((long)y);
        if (m < Integer.MIN_VALUE ||
            m > Integer.MAX_VALUE) {
            throw new ArithmeticException("overflow: mul");
        }
        return (int)m;
    }
    
    /**
     *  Multiply two non-negative integers, checking for overflow.
     * 
     * @param x a non-negative factor
     * @param y a non-negative factor
     * @return the product <code>x*y</code>
     * @throws ArithmeticException if the result can not be represented as
     * an int
     */
    private static int mulPosAndCheck(int x, int y) {
        /* assert x>=0 && y>=0; */
        long m = ((long)x)*((long)y);
        if (m > Integer.MAX_VALUE) {
            throw new ArithmeticException("overflow: mulPos");
        }
        return (int)m;
    }
    
    /** 
     * Add two integers, checking for overflow.
     * 
     * @param x an addend
     * @param y an addend
     * @return the sum <code>x+y</code>
     * @throws ArithmeticException if the result can not be represented as
     * an int
     */
    private static int addAndCheck(int x, int y) {
        long s = (long)x+(long)y;
        if (s < Integer.MIN_VALUE ||
            s > Integer.MAX_VALUE) {
            throw new ArithmeticException("overflow: add");
        }
        return (int)s;
    }
    
    /** 
     * Subtract two integers, checking for overflow.
     * 
     * @param x the minuend
     * @param y the subtrahend
     * @return the difference <code>x-y</code>
     * @throws ArithmeticException if the result can not be represented as
     * an int
     */
    private static int subAndCheck(int x, int y) {
        long s = (long)x-(long)y;
        if (s < Integer.MIN_VALUE ||
            s > Integer.MAX_VALUE) {
            throw new ArithmeticException("overflow: add");
        }
        return (int)s;
    }
    
    /**
     * <p>Adds the value of this fraction to another, returning the result in reduced form.
     * The algorithm follows Knuth, 4.5.1.</p>
     *
     * @param fraction  the fraction to add, must not be <code>null</code>
     * @return a <code>Fraction</code> instance with the resulting values
     * @throws IllegalArgumentException if the fraction is <code>null</code>
     * @throws ArithmeticException if the resulting numerator or denominator exceeds
     *  <code>Integer.MAX_VALUE</code>
     */
    public Fraction add(Fraction fraction) {
        return addSub(fraction, true /* add */);
    }
    /**
     * <p>Subtracts the value of another fraction from the value of this one, 
     * returning the result in reduced form.</p>
     *
     * @param fraction  the fraction to subtract, must not be <code>null</code>
     * @return a <code>Fraction</code> instance with the resulting values
     * @throws IllegalArgumentException if the fraction is <code>null</code>
     * @throws ArithmeticException if the resulting numerator or denominator
     *   cannot be represented in an <code>int</code>.
     */
    public Fraction subtract(Fraction fraction) {
        return addSub(fraction, false /* subtract */);
    }
    /** 
     * Implement add and subtract using algorithm described in Knuth 4.5.1.
     * 
     * @param fraction the fraction to subtract, must not be <code>null</code>
     * @param isAdd true to add, false to subtract
     * @return a <code>Fraction</code> instance with the resulting values
     * @throws IllegalArgumentException if the fraction is <code>null</code>
     * @throws ArithmeticException if the resulting numerator or denominator
     *   cannot be represented in an <code>int</code>.
     */
    private Fraction addSub(Fraction fraction, boolean isAdd) {
        if (fraction == null) {
            throw new IllegalArgumentException("The fraction must not be null");
        }
        // zero is identity for addition.
        if (numerator == 0) {
            return isAdd ? fraction : fraction.negate();
        }
        if (fraction.numerator == 0) {
            return this;
        }     
        // if denominators are randomly distributed, d1 will be 1 about 61%
        // of the time.
        int d1 = greatestCommonDivisor(denominator, fraction.denominator);
        if (d1==1) {
            // result is ( (u*v" +/- u"v) / u"v")
            int uvp = mulAndCheck(numerator, fraction.denominator);
            int upv = mulAndCheck(fraction.numerator, denominator);
            return new Fraction
                (isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv),
                 mulPosAndCheck(denominator, fraction.denominator));
        }
        // the quantity "t" requires 65 bits of precision; see knuth 4.5.1
        // exercise 7.  we"re going to use a BigInteger.
        // t = u(v"/d1) +/- v(u"/d1)
        BigInteger uvp = BigInteger.valueOf(numerator)
            .multiply(BigInteger.valueOf(fraction.denominator/d1));
        BigInteger upv = BigInteger.valueOf(fraction.numerator)
            .multiply(BigInteger.valueOf(denominator/d1));
        BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
        // but d2 doesn"t need extra precision because
        // d2 = gcd(t,d1) = gcd(t mod d1, d1)
        int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
        int d2 = (tmodd1==0)?d1:greatestCommonDivisor(tmodd1, d1);
        // result is (t/d2) / (u"/d1)(v"/d2)
        BigInteger w = t.divide(BigInteger.valueOf(d2));
        if (w.bitLength() > 31) {
            throw new ArithmeticException
                ("overflow: numerator too large after multiply");
        }
        return new Fraction
            (w.intValue(),
             mulPosAndCheck(denominator/d1, fraction.denominator/d2));
    }
    /**
     * <p>Multiplies the value of this fraction by another, returning the 
     * result in reduced form.</p>
     *
     * @param fraction  the fraction to multiply by, must not be <code>null</code>
     * @return a <code>Fraction</code> instance with the resulting values
     * @throws IllegalArgumentException if the fraction is <code>null</code>
     * @throws ArithmeticException if the resulting numerator or denominator exceeds
     *  <code>Integer.MAX_VALUE</code>
     */
    public Fraction multiplyBy(Fraction fraction) {
        if (fraction == null) {
            throw new IllegalArgumentException("The fraction must not be null");
        }
        if (numerator == 0 || fraction.numerator == 0) {
            return ZERO;
        }
        // knuth 4.5.1
        // make sure we don"t overflow unless the result *must* overflow.
        int d1 = greatestCommonDivisor(numerator, fraction.denominator);
        int d2 = greatestCommonDivisor(fraction.numerator, denominator);
        return getReducedFraction
            (mulAndCheck(numerator/d1, fraction.numerator/d2),
             mulPosAndCheck(denominator/d2, fraction.denominator/d1));
    }
    /**
     * <p>Divide the value of this fraction by another.</p>
     *
     * @param fraction  the fraction to divide by, must not be <code>null</code>
     * @return a <code>Fraction</code> instance with the resulting values
     * @throws IllegalArgumentException if the fraction is <code>null</code>
     * @throws ArithmeticException if the fraction to divide by is zero
     * @throws ArithmeticException if the resulting numerator or denominator exceeds
     *  <code>Integer.MAX_VALUE</code>
     */
    public Fraction divideBy(Fraction fraction) {
        if (fraction == null) {
            throw new IllegalArgumentException("The fraction must not be null");
        }
        if (fraction.numerator == 0) {
            throw new ArithmeticException("The fraction to divide by must not be zero");
        }
        return multiplyBy(fraction.invert());
    }
    // Basics
    //-------------------------------------------------------------------
    /**
     * <p>Compares this fraction to another object to test if they are equal.</p>.
     *
     * <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
     *
     * @param obj the reference object with which to compare
     * @return <code>true</code> if this object is equal
     */
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj instanceof Fraction == false) {
            return false;
        }
        Fraction other = (Fraction) obj;
        return (getNumerator() == other.getNumerator() &&
                getDenominator() == other.getDenominator());
    }
    /**
     * <p>Gets a hashCode for the fraction.</p>
     *
     * @return a hash code value for this object
     */
    public int hashCode() {
        if (hashCode == 0) {
            // hashcode update should be atomic.
            hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
        }
        return hashCode;
    }
    /**
     * <p>Compares this object to another based on size.</p>
     *
     * <p>Note: this class has a natural ordering that is inconsistent
     * with equals, because, for example, equals treats 1/2 and 2/4 as
     * different, whereas compareTo treats them as equal.
     *
     * @param object  the object to compare to
     * @return -1 if this is less, 0 if equal, +1 if greater
     * @throws ClassCastException if the object is not a <code>Fraction</code>
     * @throws NullPointerException if the object is <code>null</code>
     */
    public int compareTo(Object object) {
        Fraction other = (Fraction) object;
        if (this==other) {
            return 0;
        }
        if (numerator == other.numerator && denominator == other.denominator) {
            return 0;
        }
        // otherwise see which is less
        long first = (long) numerator * (long) other.denominator;
        long second = (long) other.numerator * (long) denominator;
        if (first == second) {
            return 0;
        } else if (first < second) {
            return -1;
        } else {
            return 1;
        }
    }
    /**
     * <p>Gets the fraction as a <code>String</code>.</p>
     *
     * <p>The format used is "<i>numerator</i>/<i>denominator</i>" always.
     *
     * @return a <code>String</code> form of the fraction
     */
    public String toString() {
        if (toString == null) {
            toString = new StringBuffer(32)
                .append(getNumerator())
                .append("/")
                .append(getDenominator()).toString();
        }
        return toString;
    }
    /**
     * <p>Gets the fraction as a proper <code>String</code> in the format X Y/Z.</p>
     *
     * <p>The format used in "<i>wholeNumber</i> <i>numerator</i>/<i>denominator</i>".
     * If the whole number is zero it will be ommitted. If the numerator is zero,
     * only the whole number is returned.</p>
     *
     * @return a <code>String</code> form of the fraction
     */
    public String toProperString() {
        if (toProperString == null) {
            if (numerator == 0) {
                toProperString = "0";
            } else if (numerator == denominator) {
                toProperString = "1";
            } else if (numerator == -1 * denominator) {
                toProperString = "-1";
            } else if ((numerator>0?-numerator:numerator) < -denominator) {
                // note that we do the magnitude comparison test above with
                // NEGATIVE (not positive) numbers, since negative numbers
                // have a larger range.  otherwise numerator==Integer.MIN_VALUE
                // is handled incorrectly.
                int properNumerator = getProperNumerator();
                if (properNumerator == 0) {
                    toProperString = Integer.toString(getProperWhole());
                } else {
                    toProperString = new StringBuffer(32)
                        .append(getProperWhole()).append(" ")
                        .append(properNumerator).append("/")
                        .append(getDenominator()).toString();
                }
            } else {
                toProperString = new StringBuffer(32)
                    .append(getNumerator()).append("/")
                    .append(getDenominator()).toString();
            }
        }
        return toProperString;
    }
}





Represents a range of Number objects.

/*
 * 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>Represents a range of {@link Number} objects.</p>
 * 
 * <p>This class uses <code>double</code> comparisons. This means that it
 * is unsuitable for dealing with large <code>Long</code>, <code>BigDecimal</code>
 * or <code>BigInteger</code> numbers.</p>
 *
 * @author 
 * @author Stephen Colebourne
 * @since 1.0
 * @version $Revision: 437554 $ $Date: 2006-08-27 23:21:41 -0700 (Sun, 27 Aug 2006) $
 * 
 * 
 */
public final class NumberRange {
    /* The minimum number in this range. */
    private final Number min;
    /* The maximum number in this range. */
    private final Number max;

    /**
     * <p>Constructs a new <code>NumberRange</code> using
     * <code>number</code> as both the minimum and maximum in
     * this range.</p>
     *
     * @param num the number to use for this range
     * @throws NullPointerException if the number is <code>null</code>
     */
    public NumberRange(Number num) {
        if (num == null) {
            throw new NullPointerException("The number must not be null");
        }
        this.min = num;
        this.max = num;
    }
    /**
     * <p>Constructs a new <code>NumberRange</code> with the specified
     * minimum and maximum numbers.</p>
     * 
     * <p><em>If the maximum is less than the minimum, the range will be constructed
     * from the minimum value to the minimum value, not what you would expect!.</em></p>
     *
     * @param min the minimum number in this range
     * @param max the maximum number in this range
     * @throws NullPointerException if either the minimum or maximum number is
     *  <code>null</code>
     */
    public NumberRange(Number min, Number max) {
        if (min == null) {
            throw new NullPointerException("The minimum value must not be null");
        } else if (max == null) {
            throw new NullPointerException("The maximum value must not be null");
        }
        if (max.doubleValue() < min.doubleValue()) {
            this.min = this.max = min;
        } else {
            this.min = min;
            this.max = max;
        }
    }
    /**
     * <p>Returns the minimum number in this range.</p>
     *
     * @return the minimum number in this range
     */
    public Number getMinimum() {
        return min;
    }
    /**
     * <p>Returns the maximum number in this range.</p>
     *
     * @return the maximum number in this range
     */
    public Number getMaximum() {
        return max;
    }
    /**
     * <p>Tests whether the specified <code>number</code> occurs within
     * this range using <code>double</code> comparison.</p>
     *
     * @param number the number to test
     * @return <code>true</code> if the specified number occurs within this
     *  range; otherwise, <code>false</code>
     */
    public boolean includesNumber(Number number) {
        if (number == null) {
            return false;
        } else {
            return !(min.doubleValue() > number.doubleValue()) &&
                !(max.doubleValue() < number.doubleValue());
        }
    }
    /**
     * <p>Tests whether the specified range occurs entirely within this
     * range using <code>double</code> comparison.</p>
     *
     * @param range the range to test
     * @return <code>true</code> if the specified range occurs entirely within
     *  this range; otherwise, <code>false</code>
     */
    public boolean includesRange(NumberRange range) {
        if (range == null) {
            return false;
        } else {
            return includesNumber(range.min) && includesNumber(range.max);
        }
    }
    /**
     * <p>Tests whether the specified range overlaps with this range
     * using <code>double</code> comparison.</p>
     *
     * @param range the range to test
     * @return <code>true</code> if the specified range overlaps with this
     *  range; otherwise, <code>false</code>
     */
    public boolean overlaps(NumberRange range) {
        if (range == null) {
            return false;
        } else {
            return range.includesNumber(min) || range.includesNumber(max) || 
                includesRange(range);
        }
    }
    /**
     * <p>Indicates whether some other <code>Object</code> is
     * &quot;equal&quot; to this one.</p>
     *
     * @param obj the reference object with which to compare
     * @return <code>true</code> if this object is the same as the obj
     *  argument; <code>false</code> otherwise
     */
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        } else if (!(obj instanceof NumberRange)) {
            return false;
        } else {
            NumberRange range = (NumberRange)obj;
            return min.equals(range.min) && max.equals(range.max);
        }
    }
    /**
     * <p>Returns a hash code value for this object.</p>
     *
     * @return a hash code value for this object
     */
    public int hashCode() {
        int result = 17;
        result = 37 * result + min.hashCode();
        result = 37 * result + max.hashCode();
        return result;
    }
    /**
     * <p>Returns the string representation of this range.</p>
     *
     * <p>This string is the string representation of the minimum and
     * maximum numbers in the range, separated by a hyphen. If a number
     * is negative, then it is enclosed in parentheses.</p>
     *
     * @return the string representation of this range
     */
    public String toString() {
        StringBuffer sb = new StringBuffer();
        if (min.doubleValue() < 0) {
            sb.append("(")
                .append(min)
                .append(")");
        } else {
            sb.append(min);
        }
        sb.append("-");
        if (max.doubleValue() < 0) {
            sb.append("(")
                .append(max)
                .append(")");
        } else {
            sb.append(max);
        }
        return sb.toString();
    }
}





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;
  }
}