/******************************************************************************* * Copyright (c) 2007, 2014 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation * Semantum Oy - improved output precision control *******************************************************************************/ package org.simantics.utils.format; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; /** * @author Antti Villberg * @author Tuukka Lehtonen */ public class FormattingUtil { private int floatDigits; private int doubleDigits; private double lowLimit; private double highLimit; private DecimalFormatSymbols decimalFormatSymbols; private DecimalFormat flow; private DecimalFormat[] fmiddles; private DecimalFormat fhigh; private DecimalFormat dlow; private DecimalFormat[] dmiddles; private DecimalFormat dhigh; public FormattingUtil(int floatDigits, int doubleDigits) { this(floatDigits, doubleDigits, Locale.getDefault()); } public FormattingUtil(int floatDigits, int doubleDigits, Locale locale) { this(floatDigits, doubleDigits, 0.01, 1e6, locale); } public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale) { this.floatDigits = floatDigits; this.doubleDigits = doubleDigits; this.lowLimit = lowLimit; this.highLimit = highLimit; this.decimalFormatSymbols = DecimalFormatSymbols.getInstance(locale != null ? locale : Locale.getDefault()); initFormats(); } private void initFormats() { this.flow = createLowFormat(floatDigits); double exp = Math.log10(highLimit); int formatCount = Math.max(1, (int) Math.ceil(exp)); this.fmiddles = createMiddleFormats(formatCount, floatDigits); this.fhigh = createHighFormat(floatDigits); this.dlow = createLowFormat(doubleDigits); this.dmiddles = createMiddleFormats(formatCount, doubleDigits); this.dhigh = createHighFormat(doubleDigits); } private DecimalFormat createLowFormat(int digitCount) { StringBuilder fmt = new StringBuilder(); fmt.append("0."); for (int i = 0; i < digitCount; ++i) fmt.append('#'); //System.out.println(fmt.toString()); return new DecimalFormat(fmt.toString(), decimalFormatSymbols); } private DecimalFormat createHighFormat(int digitCount) { StringBuilder fmt = new StringBuilder(); fmt.append("##0"); if (digitCount > 3) fmt.append("."); for (int i = 3; i < digitCount; ++i) fmt.append('#'); fmt.append("E0"); //System.out.println(fmt.toString()); return new DecimalFormat(fmt.toString(), decimalFormatSymbols); } private DecimalFormat[] createMiddleFormats(int formatCount, int digitCount) { DecimalFormat[] middles = new DecimalFormat[formatCount]; for (int exp10 = 0; exp10 < formatCount; ++exp10) { StringBuilder fmt = new StringBuilder(); int digits = digitCount; for (int i = 0; i < exp10 && digits > 1; ++i, --digits) fmt.append('#'); fmt.append('0'); --digits; if (digits > 0) fmt.append('.'); for (; digits > 0; --digits) fmt.append('#'); //System.out.println(fmt.toString()); middles[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols); } return middles; } public String engineeringFormat(Object value) { if (value == null) return ""; Class clazz = value.getClass(); if (clazz == Double.class) { return formatNumber((Double) value); } else if (clazz == Float.class) { return formatNumber((Float)value); } else if (clazz == double[].class) { double[] doubles = (double[])value; StringBuilder b = new StringBuilder(); b.append("["); boolean first = true; for (double d : doubles) { if(!first) b.append(","); b.append(formatNumber(d)); first = false; } b.append("]"); return b.toString(); } else if (clazz == float[].class) { float[] floats = (float[])value; StringBuilder b = new StringBuilder(); b.append("["); boolean first = true; for (float f : floats) { if(!first) b.append(","); b.append(formatNumber(f)); first = false; } b.append("]"); return b.toString(); } else if (clazz == int[].class) { int[] ints = (int[])value; StringBuilder b = new StringBuilder(); b.append("["); boolean first = true; for (int d : ints) { if(!first) b.append(","); b.append(d); first = false; } b.append("]"); return b.toString(); } else if (clazz == String.class) { return (String) value; } else { return value.toString(); } } public String formatNumber(float v) { if (Float.isInfinite(v)) { return (v == Float.POSITIVE_INFINITY) ? "\u221E" : "-\u221E"; } else if (Float.isNaN(v)) { return "NaN"; } else { float abs = Math.abs(v); if (abs < 1.0f && abs >= (float)lowLimit) { return flow.format(v); } else if (abs >= 1.0f && abs < (float)highLimit) { double exp = Math.log10(abs); int expi = (int) Math.floor(exp); // System.out.println("format(" + v + ")"); // System.out.println("exp: " + exp); // System.out.println("expi: " + expi); if (expi < fmiddles.length) { return fmiddles[expi].format(v); } } return postprocess( fhigh.format(v) ); } } public String formatNumber(double v) { if (Double.isInfinite(v)) { return (v == Double.POSITIVE_INFINITY) ? "\u221E" : "-\u221E"; } else if (Double.isNaN(v)) { return "NaN"; } else { double abs = Math.abs(v); if (abs < 1.0 && abs >= lowLimit) { return dlow.format(v); } else if (abs >= 1.0 && abs < highLimit) { double exp = Math.log10(abs); int expi = (int) Math.floor(exp); // System.out.println("format(" + v + ")"); // System.out.println("exp: " + exp); // System.out.println("expi: " + expi); if (expi < dmiddles.length) { return dmiddles[expi].format(v); } } return postprocess( dhigh.format(v) ); } } private static String postprocess(String s) { if (s.endsWith("E0")) return s.substring(0, s.length() - 2); return s.replace('E', 'e'); } public static String formatNumberLocale(Object num, int minPrecision, int maxPrecision, String languageTag) { NumberFormat format = NumberFormat.getNumberInstance(Locale.forLanguageTag(languageTag)); format.setMaximumFractionDigits(maxPrecision); format.setMinimumFractionDigits(minPrecision); if (num instanceof java.lang.Number) { double doubleValue = ((java.lang.Number)num).doubleValue(); if(Double.isFinite(doubleValue)) return format.format(doubleValue); else if(Double.isNaN(doubleValue)) return "NaN"; else if(Double.isInfinite(doubleValue)) return "\u221e"; } throw new NumberFormatException("Number " + num + ", instanceOf " + num.getClass().getName()); } public static void main(String[] args) { FormattingUtil fu = new FormattingUtil(7, 15); System.out.println("=== DOUBLE ==="); System.out.println(fu.formatNumber(123e-3)); System.out.println(fu.formatNumber(-123e-3)); System.out.println(fu.formatNumber(Double.POSITIVE_INFINITY)); System.out.println(fu.formatNumber(Double.NEGATIVE_INFINITY)); System.out.println(fu.formatNumber(Double.NaN)); System.out.println(fu.formatNumber(0)); System.out.println(fu.formatNumber(0.25)); System.out.println(fu.formatNumber(0.1)); System.out.println(fu.formatNumber(1)); System.out.println(fu.formatNumber(-0.25)); System.out.println(fu.formatNumber(-0.1)); System.out.println(fu.formatNumber(-1)); System.out.println(fu.formatNumber(0.9999)); System.out.println(fu.formatNumber(0.0999999999999999999)); System.out.println(fu.formatNumber(0.0099999999999999999999)); System.out.println(fu.formatNumber(0.004541234)); System.out.println(fu.formatNumber(0.00099999999999999999999)); System.out.println(fu.formatNumber(0.000099999999999999999999)); System.out.println(fu.formatNumber(0.0000099999999999999999999)); System.out.println(fu.formatNumber(0.00000099999999999999999999)); System.out.println(fu.formatNumber(-0.9999)); System.out.println(fu.formatNumber(-0.0999999999999999999)); System.out.println(fu.formatNumber(-0.0099999999999999999999)); System.out.println(fu.formatNumber(-0.00099999999999999999999)); System.out.println(fu.formatNumber(-0.000099999999999999999999)); System.out.println(fu.formatNumber(1.234567891)); System.out.println(fu.formatNumber(12.34567891)); System.out.println(fu.formatNumber(123.4567891)); System.out.println(fu.formatNumber(1234.567891)); System.out.println(fu.formatNumber(12345.67891)); System.out.println(fu.formatNumber(123456.7891)); System.out.println(fu.formatNumber(1234567.891)); System.out.println(fu.formatNumber(1234567.8912345678)); System.out.println(fu.formatNumber(12345678.912345678)); System.out.println(fu.formatNumber(123456789.12345678)); System.out.println(fu.formatNumber(1234567891.2345678)); System.out.println(fu.formatNumber(12345678912.345678)); System.out.println(fu.formatNumber(100.0000000000000)); System.out.println(fu.formatNumber(100000.0000000000)); System.out.println(fu.formatNumber(1000000000.000000)); System.out.println(fu.formatNumber(100000000000.0000)); System.out.println(fu.formatNumber(10000000000000.00)); System.out.println(fu.formatNumber(999999.99999999999999)); System.out.println(fu.formatNumber(999999.9999999999999)); System.out.println(fu.formatNumber(999999.999999999999)); System.out.println(fu.formatNumber(999999.99999999999)); System.out.println(fu.formatNumber(999999.9999999999)); System.out.println(fu.formatNumber(999999.999999999)); System.out.println(fu.formatNumber(999999.99999999)); System.out.println(fu.formatNumber(999999.9999999)); System.out.println(fu.formatNumber(999999.999999)); System.out.println(fu.formatNumber(999999.99999)); System.out.println(fu.formatNumber(999999.9999)); System.out.println(fu.formatNumber(999999.999)); System.out.println(fu.formatNumber(999999.99)); System.out.println(fu.formatNumber(999999.9)); System.out.println(fu.formatNumber(999999)); System.out.println("=== FLOAT ==="); System.out.println(fu.formatNumber(123e-3f)); System.out.println(fu.formatNumber(-123e-3f)); System.out.println(fu.formatNumber(Float.POSITIVE_INFINITY)); System.out.println(fu.formatNumber(Float.NEGATIVE_INFINITY)); System.out.println(fu.formatNumber(Float.NaN)); System.out.println(fu.formatNumber(0f)); System.out.println(fu.formatNumber(0.25f)); System.out.println(fu.formatNumber(0.1f)); System.out.println(fu.formatNumber(1f)); System.out.println(fu.formatNumber(-0.25f)); System.out.println(fu.formatNumber(-0.1f)); System.out.println(fu.formatNumber(-1f)); System.out.println(fu.formatNumber(0.9999f)); System.out.println(fu.formatNumber(0.0999999999999999999f)); System.out.println(fu.formatNumber(0.0099999999999999999999f)); System.out.println(fu.formatNumber(0.004541234f)); System.out.println(fu.formatNumber(0.00099999999999999999999f)); System.out.println(fu.formatNumber(0.000099999999999999999999f)); System.out.println(fu.formatNumber(0.0000099999999999999999999f)); System.out.println(fu.formatNumber(0.00000099999999999999999999f)); System.out.println(fu.formatNumber(-0.9999f)); System.out.println(fu.formatNumber(-0.0999999999999999999f)); System.out.println(fu.formatNumber(-0.0099999999999999999999f)); System.out.println(fu.formatNumber(-0.00099999999999999999999f)); System.out.println(fu.formatNumber(-0.000099999999999999999999f)); System.out.println(fu.formatNumber(1.234567891f)); System.out.println(fu.formatNumber(12.34567891f)); System.out.println(fu.formatNumber(123.4567891f)); System.out.println(fu.formatNumber(1234.567891f)); System.out.println(fu.formatNumber(12345.67891f)); System.out.println(fu.formatNumber(123456.7891f)); System.out.println(fu.formatNumber(1234567.891f)); System.out.println(fu.formatNumber(1234567.8912345678f)); System.out.println(fu.formatNumber(12345678.912345678f)); System.out.println(fu.formatNumber(123456789.12345678f)); System.out.println(fu.formatNumber(1234567891.2345678f)); System.out.println(fu.formatNumber(12345678912.345678f)); System.out.println(fu.formatNumber(100.0000000000000f)); System.out.println(fu.formatNumber(100000.0000000000f)); System.out.println(fu.formatNumber(1000000000.000000f)); System.out.println(fu.formatNumber(100000000000.0000f)); System.out.println(fu.formatNumber(10000000000000.00f)); System.out.println(fu.formatNumber(999999.99999999999999f)); System.out.println(fu.formatNumber(999999.9999999999999f)); System.out.println(fu.formatNumber(999999.999999999999f)); System.out.println(fu.formatNumber(999999.99999999999f)); System.out.println(fu.formatNumber(999999.9999999999f)); System.out.println(fu.formatNumber(999999.999999999f)); System.out.println(fu.formatNumber(999999.99999999f)); System.out.println(fu.formatNumber(999999.9999999f)); System.out.println(fu.formatNumber(999999.999999f)); System.out.println(fu.formatNumber(999999.99999f)); System.out.println(fu.formatNumber(999999.9999f)); System.out.println(fu.formatNumber(999999.999f)); System.out.println(fu.formatNumber(999999.99f)); System.out.println(fu.formatNumber(999999.9f)); System.out.println(fu.formatNumber(999999f)); } }