/*******************************************************************************
- * Copyright (c) 2007, 2014 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2018 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
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
- * Semantum Oy - improved output precision control
+ * Semantum Oy - improved output precision control, trailing zero control
*******************************************************************************/
package org.simantics.utils.format;
private int doubleDigits;
private double lowLimit;
private double highLimit;
+ private boolean trailingZeroes;
private DecimalFormatSymbols decimalFormatSymbols;
private DecimalFormat flow;
private DecimalFormat[] fmiddles;
- private DecimalFormat fhigh;
+ private DecimalFormat[] fhighs;
private DecimalFormat dlow;
private DecimalFormat[] dmiddles;
- private DecimalFormat dhigh;
+ private DecimalFormat[] dhighs;
public FormattingUtil(int floatDigits, int doubleDigits) {
this(floatDigits, doubleDigits, Locale.getDefault());
}
-
+
+ public FormattingUtil(int floatDigits, int doubleDigits, boolean addTrailingZeroes) {
+ this(floatDigits, doubleDigits, Locale.getDefault(), addTrailingZeroes);
+ }
+
public FormattingUtil(int floatDigits, int doubleDigits, Locale locale) {
- this(floatDigits, doubleDigits, 0.01, 1e6, locale);
+ this(floatDigits, doubleDigits, 0.01, 1e6, locale, false);
}
public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale) {
+ this(floatDigits, doubleDigits, lowLimit, highLimit, locale, false);
+ }
+
+ public FormattingUtil(int floatDigits, int doubleDigits, Locale locale, boolean addTrailingZeroes) {
+ this(floatDigits, doubleDigits, 0.01, 1e6, locale, addTrailingZeroes);
+ }
+
+ public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale, boolean addTrailingZeroes) {
this.floatDigits = floatDigits;
this.doubleDigits = doubleDigits;
this.lowLimit = lowLimit;
this.highLimit = highLimit;
+ this.trailingZeroes = addTrailingZeroes;
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));
+ //System.out.println("initFormats(FLOAT; " + floatDigits + ")");
+ this.flow = createLowFormat(floatDigits);
this.fmiddles = createMiddleFormats(formatCount, floatDigits);
- this.fhigh = createHighFormat(floatDigits);
+ this.fhighs = createHighFormats(floatDigits);
+ //System.out.println("initFormats(DOUBLE; " + doubleDigits + ")");
this.dlow = createLowFormat(doubleDigits);
this.dmiddles = createMiddleFormats(formatCount, doubleDigits);
- this.dhigh = createHighFormat(doubleDigits);
+ this.dhighs = createHighFormats(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());
+ fmt.append(trailingZeroes ? '0' : '#');
+ //System.out.println("lowFormat(" + digitCount + "): " + fmt);
return new DecimalFormat(fmt.toString(), decimalFormatSymbols);
}
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());
+ int i = 0;
+ for (; i <= exp10 && digits > 0; ++i, --digits)
+ fmt.append('0');
+ if (digits <= 0) {
+ if (i <= exp10)
+ fmt.append("E0");
+ } else {
+ if (digits > 0) fmt.append('.');
+ for (; digits > 0; --digits)
+ fmt.append(trailingZeroes ? '0' : '#');
+ }
+ //System.out.println("middleFormat(" + exp10 + "; " + digitCount + "): " + fmt);
middles[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
}
return middles;
}
+ private DecimalFormat[] createHighFormats(int digitCount) {
+ // [0] = for formatting 1.234567e{6,9,...}
+ // [1] = for formatting 12.34567e{6,9,...}
+ // [2] = for formatting 123.4567e{6,9,...}
+ DecimalFormat[] highs = new DecimalFormat[3];
+ for (int exp10 = 0; exp10 < 3; ++exp10) {
+ StringBuilder fmt = new StringBuilder();
+ int digits = digitCount;
+ for (int i = 0; i <= exp10 && digits > 0; ++i, --digits)
+ fmt.append('0');
+ if (digits > 0) {
+ fmt.append(".");
+ for (; digits > 0; --digits)
+ fmt.append(trailingZeroes ? '0' : '#');
+ }
+ fmt.append("E0");
+ //System.out.println("highFormat(" + exp10 + "; " + digitCount + "): " + fmt);
+ highs[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
+ }
+ return highs;
+ }
+
public String engineeringFormat(Object value) {
if (value == null)
return "";
}
}
+ private static int highFormatterIndex(int exp10) {
+ return exp10 < 0 ? (exp10 % 3 + 3) % 3 : exp10 % 3;
+ }
+
+ private static int highFormatterIndex(float absValue) {
+ return highFormatterIndex((int) Math.floor((float) Math.log10(absValue)));
+ }
+
+ private static int highFormatterIndex(double absValue) {
+ return highFormatterIndex((int) Math.floor(Math.log10(absValue)));
+ }
+
+ private static int middleFormatterIndex(float absValue) {
+ return (int) Math.floor((float) Math.log10(absValue));
+ }
+
+ private static int middleFormatterIndex(double absValue) {
+ return (int) Math.floor(Math.log10(absValue));
+ }
+
public String formatNumber(float v) {
if (Float.isInfinite(v)) {
return (v == Float.POSITIVE_INFINITY) ? "\u221E" : "-\u221E";
return "NaN";
} else {
float abs = Math.abs(v);
- if (abs < 1.0f && abs >= (float)lowLimit) {
+ if ((abs < 1.0f && abs >= (float)lowLimit) || abs == 0.0f) {
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) {
+ int expi = middleFormatterIndex(abs);
+ if (expi < fmiddles.length)
return fmiddles[expi].format(v);
- }
}
- return postprocess( fhigh.format(v) );
+ return postprocess( fhighs[ highFormatterIndex(abs) ].format(v) );
}
}
return "NaN";
} else {
double abs = Math.abs(v);
- if (abs < 1.0 && abs >= lowLimit) {
+ if ((abs < 1.0 && abs >= lowLimit) || abs == 0.0) {
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) {
+ int expi = middleFormatterIndex(abs);
+ if (expi < dmiddles.length)
return dmiddles[expi].format(v);
- }
}
- return postprocess( dhigh.format(v) );
+ return postprocess( dhighs[ highFormatterIndex(abs) ].format(v) );
}
}
}
throw new NumberFormatException("Number " + num + ", instanceOf " + num.getClass().getName());
}
-
+
public static void main(String[] args) {
- FormattingUtil fu = new FormattingUtil(7, 15);
+ FormattingUtil fu = new FormattingUtil(7, 15, true);
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.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(1.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(-1.0));
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(999999.999));
System.out.println(fu.formatNumber(999999.99));
System.out.println(fu.formatNumber(999999.9));
+ System.out.println(fu.formatNumber(999999.0));
+ // Note that this will invoke formatNumber(float), not formatNumber(double)!
System.out.println(fu.formatNumber(999999));
System.out.println("=== FLOAT ===");
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));