From fccd5bec4ca9bbd9bdf547b304ae00e43730502c Mon Sep 17 00:00:00 2001 From: Tuukka Lehtonen Date: Fri, 23 Nov 2018 10:55:50 +0200 Subject: [PATCH] Added trailing zero visibility control for FormattingUtil Also fixed some bugs in constructing the formatters with designated smaller amount of significant digits. High-value formatter selection was made a bit more complex by the trailing zeroes option. gitlab #213 Change-Id: I9e1b159940d4058a21d6cad5080892b6e1ed2d6c --- .../utils/format/FormattingUtil.java | 160 +++++++++++------- 1 file changed, 96 insertions(+), 64 deletions(-) diff --git a/bundles/org.simantics.utils/src/org/simantics/utils/format/FormattingUtil.java b/bundles/org.simantics.utils/src/org/simantics/utils/format/FormattingUtil.java index ab88bcaf4..8b8b40dc2 100644 --- a/bundles/org.simantics.utils/src/org/simantics/utils/format/FormattingUtil.java +++ b/bundles/org.simantics.utils/src/org/simantics/utils/format/FormattingUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * 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 @@ -8,7 +8,7 @@ * * 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; @@ -27,61 +27,66 @@ public class FormattingUtil { 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); } @@ -90,19 +95,45 @@ public class FormattingUtil { 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 ""; @@ -156,6 +187,26 @@ public class FormattingUtil { } } + 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"; @@ -163,19 +214,14 @@ public class FormattingUtil { 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) ); } } @@ -186,19 +232,14 @@ public class FormattingUtil { 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) ); } } @@ -221,22 +262,22 @@ public class FormattingUtil { } 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)); @@ -281,6 +322,8 @@ public class FormattingUtil { 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 ==="); @@ -326,17 +369,6 @@ public class FormattingUtil { 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)); -- 2.47.1