package com.macfaq.text; import java.text.*; import java.io.*; import java.util.*; /** * Concrete class for formatting large and small numbers, allowing a variety * of exponential/scientific notation * @see java.util.Format * @see java.text.NumberFormat * @version 1.0.1 15 Jul 1999 * @author Elliotte Rusty Harold */ public class ExponentialFormat extends NumberFormat { // might make this only a number format DecimalFormatSymbols symbols; DecimalFormat parser; public ExponentialFormat() { this(new DecimalFormat()); } /** * Create an ExponentialFormat from the given format and the symbols * for the default locale. *
* @param format The decimal format that will parse parts of the exponential. */ public ExponentialFormat(DecimalFormat format) { this.parser = format; this.symbols = format.getDecimalFormatSymbols(); this.parser.setGroupingUsed(false); } public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) { if (Double.isNaN(number)) { toAppendTo.append(symbols.getNaN()); } else if (number < 0) { toAppendTo.append(symbols.getMinusSign()); number = -number; } // now we just have to format a non-negative number if (Double.isInfinite(number)) { toAppendTo.append(symbols.getInfinity()); } else { int maxFractionDigits = this.getMaximumFractionDigits(); if (maxFractionDigits <= 0) maxFractionDigits = 1; int maxIntegerDigits = this.getMaximumIntegerDigits(); if (maxIntegerDigits <= 0) maxIntegerDigits = 1; int minIntegerDigits = this.getMinimumIntegerDigits(); if (minIntegerDigits <= 0) minIntegerDigits = 1; int minFractionDigits = this.getMinimumFractionDigits(); if (minFractionDigits <= 0) minFractionDigits = 1; if (number == 0.0) { for (int i = 0; i < minIntegerDigits; i++) { toAppendTo.append(symbols.getZeroDigit()); } toAppendTo.append(symbols.getDecimalSeparator()); for (int i = 0; i < minFractionDigits; i++) { toAppendTo.append(symbols.getZeroDigit()); } toAppendTo.append("E+000"); } else { // positive number // find integer, fraction, and exponent // this method creates some round-off error but is relatively easy // to understand. If round-off is a concern // an alternative method that treats the double as a binary number // may be seen in the source code for java.lang.FloatingDecimal double exponent = Math.floor(Math.log(number) / Math.log(10)); double normalized = number / Math.pow(10, exponent); for (int i = 1; i < minIntegerDigits; i++) { normalized *= 10; exponent--; } parser.setMinimumFractionDigits(minFractionDigits); parser.format(normalized, toAppendTo, pos); toAppendTo.append('E'); if (exponent >= 0) toAppendTo.append('+'); toAppendTo.append((int) exponent); } } return toAppendTo; } public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) { if (number < 0) { toAppendTo.append(symbols.getMinusSign()); number = -number; } int maxFractionDigits = this.getMaximumFractionDigits(); if (maxFractionDigits <= 0) maxFractionDigits = 1; int maxIntegerDigits = this.getMaximumIntegerDigits(); if (maxIntegerDigits <= 0) maxIntegerDigits = 1; int minIntegerDigits = this.getMinimumIntegerDigits(); if (minIntegerDigits <= 0) minIntegerDigits = 1; int minFractionDigits = this.getMinimumFractionDigits(); if (minFractionDigits <= 0) minFractionDigits = 1; if (number == 0) { for (int i = 0; i < minIntegerDigits; i++) { toAppendTo.append(symbols.getZeroDigit()); } toAppendTo.append(symbols.getDecimalSeparator()); for (int i = 0; i < minFractionDigits; i++) { toAppendTo.append(symbols.getZeroDigit()); } toAppendTo.append("E+000"); } else { // positive number // find integer, fraction, and exponent int exponent = (int) Math.floor(Math.log(number) / Math.log(10)); exponent -= minIntegerDigits - 1; String digits = Long.toString(number); while (digits.length() < minIntegerDigits + maxFractionDigits) { digits += '0'; } String integerField = digits.substring(0, minIntegerDigits); String fractionField = digits.substring(minIntegerDigits, minIntegerDigits+maxFractionDigits); toAppendTo.append(integerField); toAppendTo.append(symbols.getDecimalSeparator()); toAppendTo.append(fractionField); toAppendTo.append('E'); if (exponent > 0) toAppendTo.append('+'); toAppendTo.append(exponent); } return toAppendTo; } public Number parse(String text, ParsePosition parsePosition) { int oldIndex = parsePosition.getIndex(); try { double result = parser.parse(text, parsePosition).doubleValue(); int eposition = text.toUpperCase().indexOf('E'); if (eposition != -1) { // advance past the E parsePosition.setIndex(eposition + 1); // ignore a + sign if (text.charAt(parsePosition.getIndex()) == '+') { parsePosition.setIndex(parsePosition.getIndex() + 1); } int exponent = parser.parse(text, parsePosition).intValue(); result *= Math.pow(10, exponent); } return new Double(result); } catch (Exception e) { parsePosition.setIndex(oldIndex); return null; } } public Object clone() { ExponentialFormat theClone = (ExponentialFormat) super.clone(); theClone.parser = (DecimalFormat) parser.clone(); theClone.symbols = (DecimalFormatSymbols) theClone.parser.getDecimalFormatSymbols(); return theClone; } /** * Overrides equals */ public boolean equals(Object o) { if (!super.equals(o)) return false; ExponentialFormat other = (ExponentialFormat) o; other.symbols = other.parser.getDecimalFormatSymbols(); if (!this.parser.equals(other.parser)) return false; if (!this.symbols.equals(other.symbols)) return false; return true; } /** * Overrides hashCode */ public int hashCode() { return super.hashCode() * 31 + parser.getNegativePrefix().hashCode(); } }