]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils/src/org/simantics/utils/format/FormattingUtil.java
Added trailing zero visibility control for FormattingUtil
[simantics/platform.git] / bundles / org.simantics.utils / src / org / simantics / utils / format / FormattingUtil.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2018 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
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;
14
15 import java.text.DecimalFormat;
16 import java.text.DecimalFormatSymbols;
17 import java.text.NumberFormat;
18 import java.util.Locale;
19
20 /**
21  * @author Antti Villberg
22  * @author Tuukka Lehtonen
23  */
24 public class FormattingUtil {
25
26     private int floatDigits;
27     private int doubleDigits;
28     private double lowLimit;
29     private double highLimit;
30     private boolean trailingZeroes;
31     private DecimalFormatSymbols decimalFormatSymbols;
32
33     private DecimalFormat flow;
34     private DecimalFormat[] fmiddles;
35     private DecimalFormat[] fhighs;
36
37     private DecimalFormat dlow;
38     private DecimalFormat[] dmiddles;
39     private DecimalFormat[] dhighs;
40
41     public FormattingUtil(int floatDigits, int doubleDigits) {
42         this(floatDigits, doubleDigits, Locale.getDefault());
43     }
44
45     public FormattingUtil(int floatDigits, int doubleDigits, boolean addTrailingZeroes) {
46         this(floatDigits, doubleDigits, Locale.getDefault(), addTrailingZeroes);
47     }
48
49     public FormattingUtil(int floatDigits, int doubleDigits, Locale locale) {
50         this(floatDigits, doubleDigits, 0.01, 1e6, locale, false);
51     }
52
53     public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale) {
54         this(floatDigits, doubleDigits, lowLimit, highLimit, locale, false);
55     }
56
57     public FormattingUtil(int floatDigits, int doubleDigits, Locale locale, boolean addTrailingZeroes) {
58         this(floatDigits, doubleDigits, 0.01, 1e6, locale, addTrailingZeroes);
59     }
60
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());
68         initFormats();
69     }
70
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);
82     }
83
84     private DecimalFormat createLowFormat(int digitCount) {
85         StringBuilder fmt = new StringBuilder();
86         fmt.append("0.");
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);
91     }
92
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;
98             int i = 0;
99             for (; i <= exp10 && digits > 0; ++i, --digits)
100                 fmt.append('0');
101             if (digits <= 0) {
102                 if (i <= exp10)
103                     fmt.append("E0");
104             } else {
105                 if (digits > 0) fmt.append('.');
106                 for (; digits > 0; --digits)
107                     fmt.append(trailingZeroes ? '0' : '#');
108             }
109             //System.out.println("middleFormat(" + exp10 + "; " + digitCount + "): " + fmt);
110             middles[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
111         }
112         return middles;
113     }
114
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)
124                fmt.append('0');
125             if (digits > 0) {
126                 fmt.append(".");
127                 for (; digits > 0; --digits)
128                     fmt.append(trailingZeroes ? '0' : '#');
129             }
130             fmt.append("E0");
131             //System.out.println("highFormat(" + exp10  + "; " + digitCount + "): " + fmt);
132             highs[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
133         }
134         return highs;
135     }
136
137     public String engineeringFormat(Object value) {
138         if (value == null)
139             return "";
140
141         Class<?> clazz = value.getClass();
142
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();
150             b.append("[");
151             boolean first = true;
152             for (double d : doubles) {
153                 if(!first) b.append(",");
154                 b.append(formatNumber(d));
155                 first = false;
156             }
157             b.append("]");
158             return b.toString();
159         } else if (clazz == float[].class) {
160             float[] floats = (float[])value;
161             StringBuilder b = new StringBuilder();
162             b.append("[");
163             boolean first = true;
164             for (float f : floats) {
165                 if(!first) b.append(",");
166                 b.append(formatNumber(f));
167                 first = false;
168             }
169             b.append("]");
170             return b.toString();
171         } else if (clazz == int[].class) {
172             int[] ints = (int[])value;
173             StringBuilder b = new StringBuilder();
174             b.append("[");
175             boolean first = true;
176             for (int d : ints) {
177                 if(!first) b.append(",");
178                 b.append(d);
179                 first = false;
180             }
181             b.append("]");
182             return b.toString();
183         } else if (clazz == String.class) {
184             return (String) value;
185         } else {
186             return value.toString();
187         }
188     }
189
190     private static int highFormatterIndex(int exp10) {
191         return exp10 < 0 ? (exp10 % 3 + 3) % 3 : exp10 % 3;
192     }
193
194     private static int highFormatterIndex(float absValue) {
195         return highFormatterIndex((int) Math.floor((float) Math.log10(absValue)));
196     }
197
198     private static int highFormatterIndex(double absValue) {
199         return highFormatterIndex((int) Math.floor(Math.log10(absValue)));
200     }
201
202     private static int middleFormatterIndex(float absValue) {
203         return (int) Math.floor((float) Math.log10(absValue));
204     }
205     
206     private static int middleFormatterIndex(double absValue) {
207         return (int) Math.floor(Math.log10(absValue));
208     }
209     
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)) {
214             return "NaN";
215         } else {
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);
223             }
224             return postprocess( fhighs[ highFormatterIndex(abs) ].format(v) );
225         }
226     }
227
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)) {
232             return "NaN";
233         } else {
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);
241             }
242             return postprocess( dhighs[ highFormatterIndex(abs) ].format(v) );
243         }
244     }
245
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');
250     }
251
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";
262         } 
263         throw new NumberFormatException("Number " + num + ", instanceOf " + num.getClass().getName());
264     }    
265
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));
328
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));
376     }
377
378 }