Java/Data Type/Rational — различия между версиями

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

Текущая версия на 09:32, 1 июня 2010

Immutable class for holding a rational number without loss of precision

   <source lang="java">

/*

* Rational.java
*
* This class is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses.  Similarly, I release this Java version under the
* same license, though I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I"ll post it on my site.
*
* If you make use of this code, I"d appreciate hearing about it.
*   drew.noakes@drewnoakes.ru
* Latest version of this software kept at
*   http://drewnoakes.ru/
*
* Created on 6 May 2002, 18:06
* Updated 26 Aug 2002 by Drew
* - Added toSimpleString() method, which returns a simplified and hopefully more
*   readable version of the Rational.  i.e. 2/10 -> 1/5, and 10/2 -> 5
* Modified 29 Oct 2002 (v1.2)
* - Improved toSimpleString() to factor more complex rational numbers into
*   a simpler form
*     i.e.
*       10/15 -> 2/3
* - toSimpleString() now accepts a boolean flag, "allowDecimals" which will
*   display the rational number in decimal form if it fits within 5 digits
*     i.e.
*       3/4 -> 0.75 when allowDecimal == true
*/

import java.io.Serializable; /**

* Immutable class for holding a rational number without loss of precision.  Provides
* a familiar representation via toString() in form numerator/denominator.
*

* @author Drew Noakes http://drewnoakes.ru */ public class Rational extends java.lang.Number implements Serializable { /** * Holds the numerator. */ private final int numerator; /** * Holds the denominator. */ private final int denominator; private int maxSimplificationCalculations = 1000; /** * Creates a new instance of Rational. Rational objects are immutable, so * once you"ve set your numerator and denominator values here, you"re stuck * with them! */ public Rational(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; } /** * Returns the value of the specified number as a double. * This may involve rounding. * * @return the numeric value represented by this object after conversion * to type double. */ public double doubleValue() { return (double)numerator / (double)denominator; } /** * Returns the value of the specified number as a float. * This may involve rounding. * * @return the numeric value represented by this object after conversion * to type float. */ public float floatValue() { return (float)numerator / (float)denominator; } /** * Returns the value of the specified number as a byte. * This may involve rounding or truncation. This implementation simply * casts the result of doubleValue() to byte. * * @return the numeric value represented by this object after conversion * to type byte. */ public final byte byteValue() { return (byte)doubleValue(); } /** * Returns the value of the specified number as an int. * This may involve rounding or truncation. This implementation simply * casts the result of doubleValue() to int. * * @return the numeric value represented by this object after conversion * to type int. */ public final int intValue() { return (int)doubleValue(); } /** * Returns the value of the specified number as a long. * This may involve rounding or truncation. This implementation simply * casts the result of doubleValue() to long. * * @return the numeric value represented by this object after conversion * to type long. */ public final long longValue() { return (long)doubleValue(); } /** * Returns the value of the specified number as a short. * This may involve rounding or truncation. This implementation simply * casts the result of doubleValue() to short. * * @return the numeric value represented by this object after conversion * to type short. */ public final short shortValue() { return (short)doubleValue(); } /** * Returns the denominator. */ public final int getDenominator() { return this.denominator; } /** * Returns the numerator. */ public final int getNumerator() { return this.numerator; } /** * Returns the reciprocal value of this obejct as a new Rational. * @return the reciprocal in a new object */ public Rational getReciprocal() { return new Rational(this.denominator, this.numerator); } /** * Checks if this rational number is an Integer, either positive or negative. */ public boolean isInteger() { if (denominator == 1 || (denominator != 0 && (numerator % denominator == 0)) || (denominator == 0 && numerator == 0) ) { return true; } else { return false; } } /** * Returns a string representation of the object of form numerator/denominator. * @return a string representation of the object. */ public String toString() { return numerator + "/" + denominator; } /** * Returns the simplest represenation of this Rational"s value possible. */ public String toSimpleString(boolean allowDecimal) { if (denominator == 0 && numerator != 0) { return toString(); } else if (isInteger()) { return Integer.toString(intValue()); } else if (numerator != 1 && denominator % numerator == 0) { // common factor between denominator and numerator int newDenominator = denominator / numerator; return new Rational(1, newDenominator).toSimpleString(allowDecimal); } else { Rational simplifiedInstance = getSimplifiedInstance(); if (allowDecimal) { String doubleString = Double.toString(simplifiedInstance.doubleValue()); if (doubleString.length() < 5) { return doubleString; } } return simplifiedInstance.toString(); } } /** * Decides whether a brute-force simplification calculation should be avoided * by comparing the maximum number of possible calculations with some threshold. * @return true if the simplification should be performed, otherwise false */ private boolean tooComplexForSimplification() { double maxPossibleCalculations = (((double)(Math.min(denominator, numerator) - 1) / 5d) + 2); return maxPossibleCalculations > maxSimplificationCalculations; } /** * Compares two Rational instances, returning true if they are mathematically * equivalent. * @param obj the Rational to compare this instance to. * @return true if instances are mathematically equivalent, otherwise false. Will also * return false if obj is not an instance of Rational. */ public boolean equals(Object obj) { if (!(obj instanceof Rational)) { return false; } Rational that = (Rational)obj; return this.doubleValue() == that.doubleValue(); } /** * <p> * Simplifies the Rational number.

*

* Prime number series: 1, 2, 3, 5, 7, 9, 11, 13, 17

*

* To reduce a rational, need to see if both numerator and denominator are divisible * by a common factor. Using the prime number series in ascending order guarantees * the minimun number of checks required.

*

* However, generating the prime number series seems to be a hefty task. Perhaps * it"s simpler to check if both d & n are divisible by all numbers from 2 -> * (Math.min(denominator, numerator) / 2). In doing this, one can check for 2 * and 5 once, then ignore all even numbers, and all numbers ending in 0 or 5. * This leaves four numbers from every ten to check.

*

* Therefore, the max number of pairs of modulus divisions required will be:

*
     *    4   Math.min(denominator, numerator) - 1
     *   -- * ------------------------------------ + 2
     *   10                    2
     *
     *   Math.min(denominator, numerator) - 1
     * = ------------------------------------ + 2
     *                  5
     * 
    * @return a simplified instance, or if the Rational could not be simpliffied,
    *         returns itself (unchanged)
    */
   public Rational getSimplifiedInstance()
   {
       if (tooComplexForSimplification()) {
           return this;
       }
       for (int factor = 2; factor <= Math.min(denominator, numerator); factor++) {
           if ((factor % 2 == 0 && factor > 2) || (factor % 5 == 0 && factor > 5)) {
               continue;
           }
           if (denominator % factor == 0 && numerator % factor == 0) {
               // found a common factor
               return new Rational(numerator / factor, denominator / factor);
           }
       }
       return this;
   }

}

 </source>
   
  
 
  



Significant Figures

   <source lang="java">

/*

* Copyright (C) 2002-2007 Stephen Ostermiller
* http://ostermiller.org/contact.pl?regarding=Java+Utilities
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* See COPYING.TXT for details.
*/

/**

* A number with an associated number of significant figures.
* This class handles parsing numbers, determining the number
* of significant figures, adjusting the number of significant
* figures (including scientific rounding), and displaying the number.
* More information about this class is available from .
*

* When parsing a number to determine the number of significant figures, * these rules are used: *

    *
  • Non-zero digits are always significant.
  • *
  • All zeros between other significant digits are significant.
  • *
  • All zeros left of the decimal point between a significant digit and the decimal point are significant.
  • *
  • All trailing zeros to the right of the decimal point are significant.
  • *
  • If the number is contains no digits other than zero, every zero is significant.
  • *
* <p>
* When rounding a number the following rules are used:
*
    *
  • If the greatest insignificant digit is less than five, round down.
  • *
  • If the greatest insignificant digit is greater than five, round up.
  • *
  • If the greatest insignificant digit is five and followed by some non-zero digit, round up.
  • *
  • If the greatest insignificant digit is five and followed only by zeros, and the least significant * digit is odd, round up.
  • *
  • If the greatest insignificant digit is five and followed only by zeros, and the least significant * digit is even, round down.
  • *
*
* <p>
* Example of using this class to multiply numbers and display the result
* with the proper number of significant figures:
*
 String[] arguments = {"1.0", "2.0", ...}
 * SignificantFigures number;
 * int sigFigs = Integer.MAX_VALUE;
 * double result = 1D;
 * for (int i=0; i<arguments.length; i++){
 *     number = new SignificantFigures(arguments[i]);
 *     sigFigs = Math.min(sigFigs, number.getNumberSignificantFigures());
 *     result *= number.doubleValue();
 * }
 * number = new SignificantFigures(result);
 * number.setNumberSignificantFigures(sigFigs);
 * System.out.println(number);
* <p>
* Example of using this class to add numbers and display the result
* with the proper number of significant figures:
*
 String[] arguments = {"1.0", "2.0", ...}
 * SignificantFigures number;
 * int leastSD = Integer.MIN_VALUE;
 * int mostSD = Integer.MIN_VALUE;
 * double result = 0D;
 * for (int i=0; i<arguments.length; i++){
 *     number = new SignificantFigures(arguments[i]);
 *     leastSD = Math.max(leastSD, number.getLSD());
 *     mostSD = Math.max(mostSD, number.getMSD());
 *     result += number.doubleValue();
 * }
 * number = new SignificantFigures(result);
 * number.setLMSD(leastSD, mostSD);
 * System.out.println(number);
*
* @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
* @since ostermillerutils 1.00.00
*/

public class SignificantFigures extends Number {

 /**
  *
  */
 private static final long serialVersionUID = -1130798283937219608L;
 /**
  * In the case the a number
  * could not be parsed, the original is stored
  * for toString purposes.
  *
  * @since ostermillerutils 1.00.00
  */
 private String original;
 /**
  * Buffer of the significant digits.
  *
  * @since ostermillerutils 1.00.00
  */
 private StringBuffer digits;
 /**
  * The exponent of the digits if a
  * decimal place were inserted after
  * the first digit.
  *
  * @since ostermillerutils 1.00.00
  */
 private int mantissa = -1;
 /**
  * positive if true, negative if false.
  *
  * @since ostermillerutils 1.00.00
  */
 private boolean sign = true;
 /**
  * True if this number has no non-zero digits.
  *
  * @since ostermillerutils 1.00.00
  */
 private boolean isZero = false;
 /**
  * Create a SignificantFigures object from a String representation of a number.
  *
  * @param number String representation of the number.
  * @throws NumberFormatException if the String is not a valid number.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(String number) throws NumberFormatException {
   original = number;
   parse(original);
 }
 /**
  * Create a SignificantFigures object from a byte.
  *
  * @param number an 8 bit integer.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(byte number){
   original = Byte.toString(number);
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Create a SignificantFigures object from a short.
  *
  * @param number a 16 bit integer.
  *
  * @since ostermillerutils 1.00.00
  */
  public SignificantFigures(short number){
   original = Short.toString(number);
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Create a SignificantFigures object from an integer.
  *
  * @param number a 32 bit integer.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(int number){
   original = String.valueOf(number);
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Create a SignificantFigures object from a long.
  *
  * @param number a 64 bit integer.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(long number){
   original = Long.toString(number);
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Create a SignificantFigures object from a float.
  *
  * @param number a 32 bit floating point.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(float number){
   original = Float.toString(number);
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Create a SignificantFigures object from a double.
  *
  * @param number a 64 bit floating point.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(double number){
   original = Double.toString(number);
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Create a SignificantFigures object from a java number such as
  * a BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, or
  * Short.
  *
  * @param number a number.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures(Number number){
   original = number.toString();
   try {
     parse(original);
   } catch (NumberFormatException nfe){
     digits = null;
   }
 }
 /**
  * Get the number of significant digits.
  * <p>
  * If this number is not a number or infinity zero
  * will be returned.
  *
  * @return the number of significant digits in this number.
  *
  * @since ostermillerutils 1.00.00
  */
 public int getNumberSignificantFigures() {
   if (digits == null) return 0;
   return digits.length();
 }
 /**
  * Adjust the number of significant figures such that the least
  * significant digit is at the given place.  This method may add
  * significant zeros to the end of this number, or remove significant
  * digits from this number.
  * <p>
  * It is possible to remove all significant digits from this number which
  * will cause the string representation of this number to become "NaN".  This
  * could become a problem if you are adding numbers and the result is close
  * to zero.  All of the significant digits may get removed, even though the
  * result could be zero with some number of significant digits.  Its is safes
  * to use the setLMSD() method which will make a zero with the appropriate
  * number of significant figures in such instances.
  * <p>
  * This method has no effect if this number is not a number or infinity.
  *
  * @param place the desired place of the least significant digit.
  * @return this number.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures setLSD(int place){
   setLMSD(place, Integer.MIN_VALUE);
   return this;
 }
 /**
  * Adjust the number of significant figures such that the least
  * significant digit is at the given place.  This method may add
  * significant zeros to the end of this number, or remove significant
  * digits from this number.
  * <p>
  * If all significant digits are removed from this number by truncating to
  * the least significant place, a zero will be created with significant figures
  * from the least to most significant places.
  * <p>
  * This method has no effect if this number is not a number or infinity.
  *
  * @param leastPlace the desired place of the least significant digit or Integer.MIN_VALUE to ignore.
  * @param mostPlace the desired place of the most significant digit or Integer.MIN_VALUE to ignore.
  * @return this number
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures setLMSD(int leastPlace, int mostPlace){
   if (digits != null && leastPlace != Integer.MIN_VALUE){
     int significantFigures = digits.length();
     int current = mantissa - significantFigures + 1;
     int newLength = significantFigures - leastPlace + current;
     if (newLength <= 0){
       if (mostPlace == Integer.MIN_VALUE){
         original = "NaN";
         digits = null;
       } else {
         newLength = mostPlace - leastPlace + 1;
         digits.setLength(newLength);
         mantissa = leastPlace;
         for (int i=0; i<newLength; i++){
           digits.setCharAt(i, "0");
         }
         isZero = true;
         sign = true;
       }
     } else {
       digits.setLength(newLength);
       for (int i=significantFigures; i<newLength; i++){
         digits.setCharAt(i, "0");
       }
     }
   }
   return this;
 }
 /**
  * Get the decimal place of the least significant digit.
  * <p>
  * If this number is not a number or infinity Integer.MIN_VALUE
  * will be returned.
  *
  * @return the decimal place of the least significant digit.
  *
  * @since ostermillerutils 1.00.00
  */
 public int getLSD(){
   if (digits == null) return Integer.MIN_VALUE;
   return mantissa - digits.length() + 1;
 }
 /**
  * Get the decimal place of the most significant digit.
  * <p>
  * If this number is not a number or infinity Integer.MIN_VALUE
  * will be returned.
  *
  * @return the decimal place of the least significant digit.
  *
  * @since ostermillerutils 1.00.00
  */
 public int getMSD(){
   if (digits == null) return Integer.MIN_VALUE;
   return mantissa + 1;
 }
 /**
  * Formats this number.
  * If the number is less than 10^-3 or greater than or equal to 10^7,
  * or the number might have an ambiguous number of significant figures,
  * scientific notation will be used.
  * <p>
  * A string such as "NaN" or "Infinity" may be returned by this method.
  *
  * @return representation of this number.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public String toString() {
   if (digits == null) return original;
   StringBuffer digits = new StringBuffer(this.digits.toString());
   int length = digits.length();
   if (mantissa <= -4 || mantissa >= 7 ||
       (mantissa >= length &&
       digits.charAt(digits.length()-1) == "0") ||
       (isZero && mantissa != 0)) {
     // use scientific notation.
     if (length > 1){
       digits.insert(1, ".");
     }
     if (mantissa != 0){
       digits.append("E" + mantissa);
     }
   } else if (mantissa <= -1){
     digits.insert(0, "0.");
     for (int i=mantissa; i<-1; i++){
       digits.insert(2, "0");
     }
   } else if (mantissa+1 == length){
     if (length > 1 && digits.charAt(digits.length()-1) == "0"){
       digits.append(".");
     }
   } else if (mantissa < length){
     digits.insert(mantissa+1, ".");
   } else {
     for (int i=length; i<=mantissa; i++){
       digits.append("0");
     }
   }
   if (!sign) {
     digits.insert(0, "-");
   }
   return digits.toString();
 }
 /**
  * Formats this number in scientific notation.
  * <p>
  * A string such as "NaN" or "Infinity" may be returned by this method.
  *
  * @return representation of this number in scientific notation.
  *
  * @since ostermillerutils 1.00.00
  */
 public String toScientificNotation() {
   if (digits == null) return original;
   StringBuffer digits = new StringBuffer(this.digits.toString());
   int length = digits.length();
   if (length > 1){
     digits.insert(1, ".");
   }
   if (mantissa != 0){
     digits.append("E" + mantissa);
   }
   if (!sign) {
     digits.insert(0, "-");
   }
   return digits.toString();
 }
 /**
  * Parsing state:
  * Initial state before anything read.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int INITIAL = 0;
 /**
  * Parsing state:
  * State in which a possible sign and
  * possible leading zeros have been read.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int LEADZEROS = 1;
 /**
  * Parsing state:
  * State in which a possible sign and
  * at least one non-zero digit
  * has been read followed by some number of
  * zeros.  The decimal place has no
  * been encountered yet.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int MIDZEROS = 2;
 /**
  * Parsing state:
  * State in which a possible sign and
  * at least one non-zero digit
  * has been read.  The decimal place has no
  * been encountered yet.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int DIGITS = 3;
 /**
  * Parsing state:
  * State in which only a possible sign,
  * leading zeros, and a decimal point
  * have been encountered.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int LEADZEROSDOT = 4;
 /**
  * Parsing state:
  * State in which a possible sign,
  * at least one nonzero digit and a
  * decimal point have been encountered.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int DIGITSDOT = 5;
 /**
  * Parsing state:
  * State in which the exponent symbol
  * "E" has been encountered.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int MANTISSA = 6;
 /**
  * Parsing state:
  * State in which the exponent symbol
  * "E" has been encountered followed
  * by a possible sign or some number
  * of digits.
  *
  * @since ostermillerutils 1.00.00
  */
 private final static int MANTISSADIGIT = 7;
 /**
  * Parse a number from the given string.
  * A valid number has an optional sign, some digits
  * with an optional decimal point, and an optional
  * scientific notation part consisting of an "E" followed
  * by an optional sign, followed by some digits.
  *
  * @param number String representation of a number.
  * @throws NumberFormatException if the string is not a valid number.
  *
  * @since ostermillerutils 1.00.00
  */
 private void parse(String number) throws NumberFormatException {
   int length = number.length();
   digits = new StringBuffer(length);
   int state = INITIAL;
   int mantissaStart = -1;
   boolean foundMantissaDigit = false;
   // sometimes we don"t know if a zero will be
   // significant or not when it is encountered.
   // keep track of the number of them so that
   // the all can be made significant if we find
   // out that they are.
   int zeroCount = 0;
   int leadZeroCount = 0;
   for (int i=0; i<length; i++){
     char c = number.charAt(i);
     switch (c){
       case ".": {
         switch (state){
           case INITIAL:
           case LEADZEROS: {
             state = LEADZEROSDOT;
           } break;
           case MIDZEROS: {
             // we now know that these zeros
             // are more than just trailing place holders.
             for (int j=0; j<zeroCount; j++){
               digits.append("0");
             }
             zeroCount = 0;
             state = DIGITSDOT;
           } break;
           case DIGITS: {
             state = DIGITSDOT;
           } break;
           default: {
             throw new NumberFormatException (
               "Unexpected character "" + c + "" at position " + i
             );
           }
         }
       } break;
       case "+":{
         switch (state){
           case INITIAL: {
             sign = true;
             state = LEADZEROS;
           } break;
           case MANTISSA: {
             state = MANTISSADIGIT;
           } break;
           default: {
             throw new NumberFormatException (
               "Unexpected character "" + c + "" at position " + i
             );
           }
         }
       } break;
       case "-": {
         switch (state){
           case INITIAL: {
             sign = false;
             state = LEADZEROS;
           } break;
           case MANTISSA: {
             state = MANTISSADIGIT;
           } break;
           default: {
             throw new NumberFormatException (
               "Unexpected character "" + c + "" at position " + i
             );
           }
         }
       } break;
       case "0": {
         switch (state){
           case INITIAL:
           case LEADZEROS: {
             // only significant if number
             // is all zeros.
             zeroCount++;
             leadZeroCount++;
             state = LEADZEROS;
           } break;
           case MIDZEROS:
           case DIGITS: {
             // only significant if followed
             // by a decimal point or nonzero digit.
             mantissa++;
             zeroCount++;
             state = MIDZEROS;
           } break;
           case LEADZEROSDOT:{
             // only significant if number
             // is all zeros.
             mantissa--;
             zeroCount++;
             state = LEADZEROSDOT;
           } break;
           case DIGITSDOT: {
             // non-leading zeros after
             // a decimal point are always
             // significant.
             digits.append(c);
           } break;
           case MANTISSA:
           case MANTISSADIGIT: {
             foundMantissaDigit = true;
             state = MANTISSADIGIT;
           } break;
           default: {
             throw new NumberFormatException (
               "Unexpected character "" + c + "" at position " + i
             );
           }
         }
       } break;
       case "1": case "2": case "3":
       case "4": case "5": case "6":
       case "7": case "8": case "9": {
         switch (state){
           case INITIAL:
           case LEADZEROS:
           case DIGITS: {
             zeroCount = 0;
             digits.append(c);
             mantissa++;
             state = DIGITS;
           } break;
           case MIDZEROS: {
             // we now know that these zeros
             // are more than just trailing place holders.
             for (int j=0; j<zeroCount; j++){
               digits.append("0");
             }
             zeroCount = 0;
             digits.append(c);
             mantissa++;
             state = DIGITS;
           } break;
           case LEADZEROSDOT:
           case DIGITSDOT: {
             zeroCount = 0;
             digits.append(c);
             state = DIGITSDOT;
           } break;
           case MANTISSA:
           case MANTISSADIGIT: {
             state = MANTISSADIGIT;
             foundMantissaDigit = true;
           } break;
           default: {
             throw new NumberFormatException (
               "Unexpected character "" + c + "" at position " + i
             );
           }
         }
       } break;
       case "E": case "e": {
         switch (state){
           case INITIAL:
           case LEADZEROS:
           case DIGITS:
           case LEADZEROSDOT:
           case DIGITSDOT: {
             // record the starting point of the mantissa
             // so we can do a substring to get it back later
             mantissaStart = i+1;
             state = MANTISSA;
           } break;
           default: {
             throw new NumberFormatException (
               "Unexpected character "" + c + "" at position " + i
             );
           }
         }
       } break;
       default: {
         throw new NumberFormatException (
           "Unexpected character "" + c + "" at position " + i
         );
       }
     }
   }
   if (mantissaStart != -1){
     // if we had found an "E"
     if (!foundMantissaDigit){
       // we didn"t actually find a mantissa to go with.
       throw new NumberFormatException (
         "No digits in mantissa."
       );
     }
     // parse the mantissa.
     mantissa += Integer.parseInt(number.substring(mantissaStart));
   }
   if (digits.length() == 0){
     if (zeroCount > 0){
       // if nothing but zeros all zeros are significant.
       for (int j=0; j<zeroCount; j++){
         digits.append("0");
       }
       mantissa += leadZeroCount;
       isZero = true;
       sign = true;
     } else {
       // a hack to catch some cases that we could catch
       // by adding a ton of extra states.  Things like:
       // "e2" "+e2" "+." "." "+" etc.
       throw new NumberFormatException (
         "No digits in number."
       );
     }
   }
 }
 /**
  * Adjust the number of digits in the number.
  * Pad the tail with zeros if too short, round the
  * number according to scientific rounding if too long, leave alone
  * if just right.
  * <p>
  * This method has no effect if this number is not a number or infinity.
  *
  * @param significantFigures desired number of significant figures.
  * @return This number.
  *
  * @since ostermillerutils 1.00.00
  */
 public SignificantFigures setNumberSignificantFigures(int significantFigures){
   if (significantFigures <= 0) throw new IllegalArgumentException("Desired number of significant figures must be positive.");
   if (digits != null) {
     int length =  digits.length();
     if (length < significantFigures){
       // number is not long enough, pad it with zeros.
       for (int i=length; i<significantFigures; i++){
         digits.append("0");
       }
     } else if (length > significantFigures){
       // number is too long chop some of it off with rounding.
       boolean addOne; // we need to round up if true.
       char firstInSig = digits.charAt(significantFigures);
       if (firstInSig < "5"){
         // first non-significant digit less than five, round down.
         addOne = false;
       } else if (firstInSig == "5"){
         // first non-significant digit equal to five
         addOne = false;
         for (int i=significantFigures+1; !addOne && i<length; i++){
           // if its followed by any non-zero digits, round up.
           if (digits.charAt(i) != "0"){
             addOne = true;
           }
         }
         if (!addOne){
           // if it was not followed by non-zero digits
           // if the last significant digit is odd round up
           // if the last significant digit is even round down
           addOne = (digits.charAt(significantFigures-1) & 1) == 1;
         }
       } else {
         // first non-significant digit greater than five, round up.
         addOne = true;
       }
       // loop to add one (and carry a one if added to a nine)
       // to the last significant digit
       for (int i=significantFigures-1; addOne && i>=0; i--){
         char digit = digits.charAt(i);
         if (digit < "9"){
           digits.setCharAt(i, (char)(digit+1));
           addOne = false;
         } else {
           digits.setCharAt(i, "0");
         }
       }
       if (addOne){
         // if the number was all nines
         digits.insert(0, "1");
         mantissa++;
       }
       // chop it to the correct number of figures.
       digits.setLength(significantFigures);
     }
   }
   return this;
 }
 /**
  * Returns the value of this number as a byte.
  *
  * @return the numeric value represented by this object after conversion to type byte.
  * @throws NumberFormatException if this number cannot be converted to a byte.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public byte byteValue() throws NumberFormatException {
   return Byte.parseByte(original);
 }
 /**
  * Returns the value of this number as a double.
  *
  * @return the numeric value represented by this object after conversion to type double.
  * @throws NumberFormatException if this number cannot be converted to a double.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public double doubleValue() throws NumberFormatException {
   return Double.parseDouble(original);
 }
 /**
  * Returns the value of this number as a float.
  *
  * @return the numeric value represented by this object after conversion to type float.
  * @throws NumberFormatException if this number cannot be converted to a float.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public float floatValue() throws NumberFormatException {
   return Float.parseFloat(original);
 }
 /**
  * Returns the value of this number as a int.
  *
  * @return the numeric value represented by this object after conversion to type int.
  * @throws NumberFormatException if this number cannot be converted to a int.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public int intValue() throws NumberFormatException {
   return Integer.parseInt(original);
 }
 /**
  * Returns the value of this number as a long.
  *
  * @return the numeric value represented by this object after conversion to type long.
  * @throws NumberFormatException if this number cannot be converted to a long.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public long longValue() throws NumberFormatException {
   return Long.parseLong(original);
 }
 /**
  * Returns the value of this number as a short.
  *
  * @return the numeric value represented by this object after conversion to type short.
  * @throws NumberFormatException if this number cannot be converted to a short.
  *
  * @since ostermillerutils 1.00.00
  */
 @Override public short shortValue() throws NumberFormatException {
   return Short.parseShort(original);
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(byte number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(double number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(float number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(int number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(long number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(Number number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(short number, int significantFigures){
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }
 /**
  * Convenience method to display a number with the correct
  * significant digits.
  *
  * @param number the number to display
  * @param significantFigures the number of significant figures to display.
  * @return the number formatted with the correct significant figures
  * @throws NumberFormatException if the String is not a valid number.
  *
  * @since ostermillerutils 1.02.07
  */
 public static String format(String number, int significantFigures) throws NumberFormatException {
   SignificantFigures sf = new SignificantFigures(number);
   sf.setNumberSignificantFigures(significantFigures);
   return sf.toString();
 }

}

 </source>