1 /*******************************************************************************
2 * Copyright (c) 2007, 2018 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 * Semantum Oy - improved output precision control, trailing zero control
12 *******************************************************************************/
13 package org.simantics.utils.format;
15 import java.text.DecimalFormat;
16 import java.text.DecimalFormatSymbols;
17 import java.text.NumberFormat;
18 import java.util.Locale;
21 * @author Antti Villberg
22 * @author Tuukka Lehtonen
24 public class FormattingUtil {
26 private int floatDigits;
27 private int doubleDigits;
28 private double lowLimit;
29 private double highLimit;
30 private boolean trailingZeroes;
31 private DecimalFormatSymbols decimalFormatSymbols;
33 private DecimalFormat flow;
34 private DecimalFormat[] fmiddles;
35 private DecimalFormat[] fhighs;
37 private DecimalFormat dlow;
38 private DecimalFormat[] dmiddles;
39 private DecimalFormat[] dhighs;
41 public FormattingUtil(int floatDigits, int doubleDigits) {
42 this(floatDigits, doubleDigits, Locale.getDefault());
45 public FormattingUtil(int floatDigits, int doubleDigits, boolean addTrailingZeroes) {
46 this(floatDigits, doubleDigits, Locale.getDefault(), addTrailingZeroes);
49 public FormattingUtil(int floatDigits, int doubleDigits, Locale locale) {
50 this(floatDigits, doubleDigits, 0.01, 1e6, locale, false);
53 public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale) {
54 this(floatDigits, doubleDigits, lowLimit, highLimit, locale, false);
57 public FormattingUtil(int floatDigits, int doubleDigits, Locale locale, boolean addTrailingZeroes) {
58 this(floatDigits, doubleDigits, 0.01, 1e6, locale, addTrailingZeroes);
61 public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale, boolean addTrailingZeroes) {
62 this.floatDigits = floatDigits;
63 this.doubleDigits = doubleDigits;
64 this.lowLimit = lowLimit;
65 this.highLimit = highLimit;
66 this.trailingZeroes = addTrailingZeroes;
67 this.decimalFormatSymbols = DecimalFormatSymbols.getInstance(locale != null ? locale : Locale.getDefault());
71 private void initFormats() {
72 double exp = Math.log10(highLimit);
73 int formatCount = Math.max(1, (int) Math.ceil(exp));
74 //System.out.println("initFormats(FLOAT; " + floatDigits + ")");
75 this.flow = createLowFormat(floatDigits);
76 this.fmiddles = createMiddleFormats(formatCount, floatDigits);
77 this.fhighs = createHighFormats(floatDigits);
78 //System.out.println("initFormats(DOUBLE; " + doubleDigits + ")");
79 this.dlow = createLowFormat(doubleDigits);
80 this.dmiddles = createMiddleFormats(formatCount, doubleDigits);
81 this.dhighs = createHighFormats(doubleDigits);
84 private DecimalFormat createLowFormat(int digitCount) {
85 StringBuilder fmt = new StringBuilder();
87 for (int i = 0; i < digitCount; ++i)
88 fmt.append(trailingZeroes ? '0' : '#');
89 //System.out.println("lowFormat(" + digitCount + "): " + fmt);
90 return new DecimalFormat(fmt.toString(), decimalFormatSymbols);
93 private DecimalFormat[] createMiddleFormats(int formatCount, int digitCount) {
94 DecimalFormat[] middles = new DecimalFormat[formatCount];
95 for (int exp10 = 0; exp10 < formatCount; ++exp10) {
96 StringBuilder fmt = new StringBuilder();
97 int digits = digitCount;
99 for (; i <= exp10 && digits > 0; ++i, --digits)
105 if (digits > 0) fmt.append('.');
106 for (; digits > 0; --digits)
107 fmt.append(trailingZeroes ? '0' : '#');
109 //System.out.println("middleFormat(" + exp10 + "; " + digitCount + "): " + fmt);
110 middles[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
115 private DecimalFormat[] createHighFormats(int digitCount) {
116 // [0] = for formatting 1.234567e{6,9,...}
117 // [1] = for formatting 12.34567e{6,9,...}
118 // [2] = for formatting 123.4567e{6,9,...}
119 DecimalFormat[] highs = new DecimalFormat[3];
120 for (int exp10 = 0; exp10 < 3; ++exp10) {
121 StringBuilder fmt = new StringBuilder();
122 int digits = digitCount;
123 for (int i = 0; i <= exp10 && digits > 0; ++i, --digits)
127 for (; digits > 0; --digits)
128 fmt.append(trailingZeroes ? '0' : '#');
131 //System.out.println("highFormat(" + exp10 + "; " + digitCount + "): " + fmt);
132 highs[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
137 public String engineeringFormat(Object value) {
141 Class<?> clazz = value.getClass();
143 if (clazz == Double.class) {
144 return formatNumber((Double) value);
145 } else if (clazz == Float.class) {
146 return formatNumber((Float)value);
147 } else if (clazz == double[].class) {
148 double[] doubles = (double[])value;
149 StringBuilder b = new StringBuilder();
151 boolean first = true;
152 for (double d : doubles) {
153 if(!first) b.append(",");
154 b.append(formatNumber(d));
159 } else if (clazz == float[].class) {
160 float[] floats = (float[])value;
161 StringBuilder b = new StringBuilder();
163 boolean first = true;
164 for (float f : floats) {
165 if(!first) b.append(",");
166 b.append(formatNumber(f));
171 } else if (clazz == int[].class) {
172 int[] ints = (int[])value;
173 StringBuilder b = new StringBuilder();
175 boolean first = true;
177 if(!first) b.append(",");
183 } else if (clazz == String.class) {
184 return (String) value;
186 return value.toString();
190 private static int highFormatterIndex(int exp10) {
191 return exp10 < 0 ? (exp10 % 3 + 3) % 3 : exp10 % 3;
194 private static int highFormatterIndex(float absValue) {
195 return highFormatterIndex((int) Math.floor((float) Math.log10(absValue)));
198 private static int highFormatterIndex(double absValue) {
199 return highFormatterIndex((int) Math.floor(Math.log10(absValue)));
202 private static int middleFormatterIndex(float absValue) {
203 return (int) Math.floor((float) Math.log10(absValue));
206 private static int middleFormatterIndex(double absValue) {
207 return (int) Math.floor(Math.log10(absValue));
210 public String formatNumber(float v) {
211 if (Float.isInfinite(v)) {
212 return (v == Float.POSITIVE_INFINITY) ? "\u221E" : "-\u221E";
213 } else if (Float.isNaN(v)) {
216 float abs = Math.abs(v);
217 if ((abs < 1.0f && abs >= (float)lowLimit) || abs == 0.0f) {
218 return flow.format(v);
219 } else if (abs >= 1.0f && abs < (float)highLimit) {
220 int expi = middleFormatterIndex(abs);
221 if (expi < fmiddles.length)
222 return fmiddles[expi].format(v);
224 return postprocess( fhighs[ highFormatterIndex(abs) ].format(v) );
228 public String formatNumber(double v) {
229 if (Double.isInfinite(v)) {
230 return (v == Double.POSITIVE_INFINITY) ? "\u221E" : "-\u221E";
231 } else if (Double.isNaN(v)) {
234 double abs = Math.abs(v);
235 if ((abs < 1.0 && abs >= lowLimit) || abs == 0.0) {
236 return dlow.format(v);
237 } else if (abs >= 1.0 && abs < highLimit) {
238 int expi = middleFormatterIndex(abs);
239 if (expi < dmiddles.length)
240 return dmiddles[expi].format(v);
242 return postprocess( dhighs[ highFormatterIndex(abs) ].format(v) );
246 private static String postprocess(String s) {
247 if (s.endsWith("E0"))
248 return s.substring(0, s.length() - 2);
249 return s.replace('E', 'e');
252 public static String formatNumberLocale(Object num, int minPrecision, int maxPrecision, String languageTag) {
253 NumberFormat format = NumberFormat.getNumberInstance(Locale.forLanguageTag(languageTag));
254 format.setMaximumFractionDigits(maxPrecision);
255 format.setMinimumFractionDigits(minPrecision);
256 if (num instanceof java.lang.Number) {
257 double doubleValue = ((java.lang.Number)num).doubleValue();
258 if(Double.isFinite(doubleValue))
259 return format.format(doubleValue);
260 else if(Double.isNaN(doubleValue)) return "NaN";
261 else if(Double.isInfinite(doubleValue)) return "\u221e";
263 throw new NumberFormatException("Number " + num + ", instanceOf " + num.getClass().getName());
266 public static void main(String[] args) {
267 FormattingUtil fu = new FormattingUtil(7, 15, true);
268 System.out.println("=== DOUBLE ===");
269 System.out.println(fu.formatNumber(123e-3));
270 System.out.println(fu.formatNumber(-123e-3));
271 System.out.println(fu.formatNumber(Double.POSITIVE_INFINITY));
272 System.out.println(fu.formatNumber(Double.NEGATIVE_INFINITY));
273 System.out.println(fu.formatNumber(Double.NaN));
274 System.out.println(fu.formatNumber(0.0));
275 System.out.println(fu.formatNumber(0.25));
276 System.out.println(fu.formatNumber(0.1));
277 System.out.println(fu.formatNumber(1.0));
278 System.out.println(fu.formatNumber(-0.25));
279 System.out.println(fu.formatNumber(-0.1));
280 System.out.println(fu.formatNumber(-1.0));
281 System.out.println(fu.formatNumber(0.9999));
282 System.out.println(fu.formatNumber(0.0999999999999999999));
283 System.out.println(fu.formatNumber(0.0099999999999999999999));
284 System.out.println(fu.formatNumber(0.004541234));
285 System.out.println(fu.formatNumber(0.00099999999999999999999));
286 System.out.println(fu.formatNumber(0.000099999999999999999999));
287 System.out.println(fu.formatNumber(0.0000099999999999999999999));
288 System.out.println(fu.formatNumber(0.00000099999999999999999999));
289 System.out.println(fu.formatNumber(-0.9999));
290 System.out.println(fu.formatNumber(-0.0999999999999999999));
291 System.out.println(fu.formatNumber(-0.0099999999999999999999));
292 System.out.println(fu.formatNumber(-0.00099999999999999999999));
293 System.out.println(fu.formatNumber(-0.000099999999999999999999));
294 System.out.println(fu.formatNumber(1.234567891));
295 System.out.println(fu.formatNumber(12.34567891));
296 System.out.println(fu.formatNumber(123.4567891));
297 System.out.println(fu.formatNumber(1234.567891));
298 System.out.println(fu.formatNumber(12345.67891));
299 System.out.println(fu.formatNumber(123456.7891));
300 System.out.println(fu.formatNumber(1234567.891));
301 System.out.println(fu.formatNumber(1234567.8912345678));
302 System.out.println(fu.formatNumber(12345678.912345678));
303 System.out.println(fu.formatNumber(123456789.12345678));
304 System.out.println(fu.formatNumber(1234567891.2345678));
305 System.out.println(fu.formatNumber(12345678912.345678));
306 System.out.println(fu.formatNumber(100.0000000000000));
307 System.out.println(fu.formatNumber(100000.0000000000));
308 System.out.println(fu.formatNumber(1000000000.000000));
309 System.out.println(fu.formatNumber(100000000000.0000));
310 System.out.println(fu.formatNumber(10000000000000.00));
311 System.out.println(fu.formatNumber(999999.99999999999999));
312 System.out.println(fu.formatNumber(999999.9999999999999));
313 System.out.println(fu.formatNumber(999999.999999999999));
314 System.out.println(fu.formatNumber(999999.99999999999));
315 System.out.println(fu.formatNumber(999999.9999999999));
316 System.out.println(fu.formatNumber(999999.999999999));
317 System.out.println(fu.formatNumber(999999.99999999));
318 System.out.println(fu.formatNumber(999999.9999999));
319 System.out.println(fu.formatNumber(999999.999999));
320 System.out.println(fu.formatNumber(999999.99999));
321 System.out.println(fu.formatNumber(999999.9999));
322 System.out.println(fu.formatNumber(999999.999));
323 System.out.println(fu.formatNumber(999999.99));
324 System.out.println(fu.formatNumber(999999.9));
325 System.out.println(fu.formatNumber(999999.0));
326 // Note that this will invoke formatNumber(float), not formatNumber(double)!
327 System.out.println(fu.formatNumber(999999));
329 System.out.println("=== FLOAT ===");
330 System.out.println(fu.formatNumber(123e-3f));
331 System.out.println(fu.formatNumber(-123e-3f));
332 System.out.println(fu.formatNumber(Float.POSITIVE_INFINITY));
333 System.out.println(fu.formatNumber(Float.NEGATIVE_INFINITY));
334 System.out.println(fu.formatNumber(Float.NaN));
335 System.out.println(fu.formatNumber(0f));
336 System.out.println(fu.formatNumber(0.25f));
337 System.out.println(fu.formatNumber(0.1f));
338 System.out.println(fu.formatNumber(1f));
339 System.out.println(fu.formatNumber(-0.25f));
340 System.out.println(fu.formatNumber(-0.1f));
341 System.out.println(fu.formatNumber(-1f));
342 System.out.println(fu.formatNumber(0.9999f));
343 System.out.println(fu.formatNumber(0.0999999999999999999f));
344 System.out.println(fu.formatNumber(0.0099999999999999999999f));
345 System.out.println(fu.formatNumber(0.004541234f));
346 System.out.println(fu.formatNumber(0.00099999999999999999999f));
347 System.out.println(fu.formatNumber(0.000099999999999999999999f));
348 System.out.println(fu.formatNumber(0.0000099999999999999999999f));
349 System.out.println(fu.formatNumber(0.00000099999999999999999999f));
350 System.out.println(fu.formatNumber(-0.9999f));
351 System.out.println(fu.formatNumber(-0.0999999999999999999f));
352 System.out.println(fu.formatNumber(-0.0099999999999999999999f));
353 System.out.println(fu.formatNumber(-0.00099999999999999999999f));
354 System.out.println(fu.formatNumber(-0.000099999999999999999999f));
355 System.out.println(fu.formatNumber(1.234567891f));
356 System.out.println(fu.formatNumber(12.34567891f));
357 System.out.println(fu.formatNumber(123.4567891f));
358 System.out.println(fu.formatNumber(1234.567891f));
359 System.out.println(fu.formatNumber(12345.67891f));
360 System.out.println(fu.formatNumber(123456.7891f));
361 System.out.println(fu.formatNumber(1234567.891f));
362 System.out.println(fu.formatNumber(1234567.8912345678f));
363 System.out.println(fu.formatNumber(12345678.912345678f));
364 System.out.println(fu.formatNumber(123456789.12345678f));
365 System.out.println(fu.formatNumber(1234567891.2345678f));
366 System.out.println(fu.formatNumber(12345678912.345678f));
367 System.out.println(fu.formatNumber(100.0000000000000f));
368 System.out.println(fu.formatNumber(100000.0000000000f));
369 System.out.println(fu.formatNumber(1000000000.000000f));
370 System.out.println(fu.formatNumber(100000000000.0000f));
371 System.out.println(fu.formatNumber(10000000000000.00f));
372 System.out.println(fu.formatNumber(999999.999f));
373 System.out.println(fu.formatNumber(999999.99f));
374 System.out.println(fu.formatNumber(999999.9f));
375 System.out.println(fu.formatNumber(999999f));