📄 significantfigures.java
字号:
/* * Routines for working with numbers in scientific notation. * Copyright (C) 2002 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. */package com.Ostermiller.util;/** * 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 <a target="_top" href= * "http://ostermiller.org/utils/SignificantFigures.html">ostermiller.org</a>. * <p> * When parsing a number to determine the number of significant figures, * these rules are used: * <ul> * <li>Non-zero digits are always significant.</li> * <li>All zeros between other significant digits or between a significant * digit and the decimal point are significant.</li> * <li>All trailing zeros to the right of the decimal point are significant.</li> * <li>If the number is contains no digits other than zero, every zero is significant.</li> * </ul> * <p> * When rounding a number the following rules are used: * <ul> * <li>If the greatest insignificant digit is less than five, round down.</li> * <li>If the greatest insignificant digit is greater than five, round up.</li> * <li>If the greatest insignificant digit is five and followed by some non-zero digit, round up.</li> * <li>If the greatest insignificant digit is five and followed only by zeros, and the least significant * digit is odd, round up.</li> * <li>If the greatest insignificant digit is five and followed only by zeros, and the least significant * digit is even, round down.</li> * </ul> * * <p> * Example of using this class to multiply numbers and display the result * with the proper number of significant figures:<br> * <pre> String[] args = {"1.0", "2.0", ...} * SignificantFigures number; * int sigs = Integer.MAX_VALUE; * double result = 1D; * for (int i=0; i<args.length; i++){ * number = new SignificantFigures(args[i]); * sigs = Math.min(sigs, number.getNumberSignificantFigures()); * result *= number.doubleValue(); * } * number = new SignificantFigures(result); * number.setNumberSignificantFigures(sigs); * System.out.println(number);</pre> * <p> * Example of using this class to add numbers and display the result * with the proper number of significant figures:<br> * <pre> String[] args = {"1.0", "2.0", ...} * SignificantFigures number; * int lsd = Integer.MIN_VALUE; * int msd = Integer.MIN_VALUE; * double result = 0D; * for (int i=0; i<args.length; i++){ * number = new SignificantFigures(args[i]); * lsd = Math.max(lsd, number.getLSD()); * msd = Math.max(msd, number.getMSD()); * result += number.doubleValue(); * } * number = new SignificantFigures(result); * number.setLMSD(lsd, msd); * System.out.println(number);</pre> * * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities * @since ostermillerutils 1.00.00 */public class SignificantFigures extends Number { /** * 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 = Integer.toString(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; } } /*public static void main(String[] args){ int significantFigures = 0; int lsd = Integer.MIN_VALUE; int msd = Integer.MAX_VALUE; for (int i=0; i<args.length; i++){ if (args[i].equals("--sigfigs")){ i++; significantFigures = Integer.parseInt(args[i]); } else if (args[i].equals("--lsd")){ i++; lsd = Integer.parseInt(args[i]); } else if (args[i].equals("--msd")){ i++; msd = Integer.parseInt(args[i]); } else { SignificantFigures sf = new SignificantFigures(args[i]); System.out.print(args[i] + " "); System.out.print(sf.getNumberSignificantFigures() + " "); System.out.print(sf.getLSD() + " "); if (significantFigures>0) sf.setNumberSignificantFigures(significantFigures); sf.setLMSD(lsd, msd); System.out.print(sf.toString() + " "); System.out.println(sf.toScientificNotation()); } } }*/ /** * 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 leas * 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 */ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -