1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2014 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 * Semantum Oy - improved output precision control
\r
12 *******************************************************************************/
\r
13 package org.simantics.utils.format;
\r
15 import java.text.DecimalFormat;
\r
16 import java.text.DecimalFormatSymbols;
\r
17 import java.text.NumberFormat;
\r
18 import java.util.Locale;
\r
21 * @author Antti Villberg
\r
22 * @author Tuukka Lehtonen
\r
24 public class FormattingUtil {
\r
26 private int floatDigits;
\r
27 private int doubleDigits;
\r
28 private double lowLimit;
\r
29 private double highLimit;
\r
30 private DecimalFormatSymbols decimalFormatSymbols;
\r
32 private DecimalFormat flow;
\r
33 private DecimalFormat[] fmiddles;
\r
34 private DecimalFormat fhigh;
\r
36 private DecimalFormat dlow;
\r
37 private DecimalFormat[] dmiddles;
\r
38 private DecimalFormat dhigh;
\r
40 public FormattingUtil(int floatDigits, int doubleDigits) {
\r
41 this(floatDigits, doubleDigits, Locale.getDefault());
\r
44 public FormattingUtil(int floatDigits, int doubleDigits, Locale locale) {
\r
45 this(floatDigits, doubleDigits, 0.01, 1e6, locale);
\r
48 public FormattingUtil(int floatDigits, int doubleDigits, double lowLimit, double highLimit, Locale locale) {
\r
49 this.floatDigits = floatDigits;
\r
50 this.doubleDigits = doubleDigits;
\r
51 this.lowLimit = lowLimit;
\r
52 this.highLimit = highLimit;
\r
53 this.decimalFormatSymbols = DecimalFormatSymbols.getInstance(locale != null ? locale : Locale.getDefault());
\r
57 private void initFormats() {
\r
58 this.flow = createLowFormat(floatDigits);
\r
59 double exp = Math.log10(highLimit);
\r
60 int formatCount = Math.max(1, (int) Math.ceil(exp));
\r
61 this.fmiddles = createMiddleFormats(formatCount, floatDigits);
\r
62 this.fhigh = createHighFormat(floatDigits);
\r
63 this.dlow = createLowFormat(doubleDigits);
\r
64 this.dmiddles = createMiddleFormats(formatCount, doubleDigits);
\r
65 this.dhigh = createHighFormat(doubleDigits);
\r
68 private DecimalFormat createLowFormat(int digitCount) {
\r
69 StringBuilder fmt = new StringBuilder();
\r
71 for (int i = 0; i < digitCount; ++i)
\r
73 //System.out.println(fmt.toString());
\r
74 return new DecimalFormat(fmt.toString(), decimalFormatSymbols);
\r
77 private DecimalFormat createHighFormat(int digitCount) {
\r
78 StringBuilder fmt = new StringBuilder();
\r
80 if (digitCount > 3) fmt.append(".");
\r
81 for (int i = 3; i < digitCount; ++i)
\r
84 //System.out.println(fmt.toString());
\r
85 return new DecimalFormat(fmt.toString(), decimalFormatSymbols);
\r
88 private DecimalFormat[] createMiddleFormats(int formatCount, int digitCount) {
\r
89 DecimalFormat[] middles = new DecimalFormat[formatCount];
\r
90 for (int exp10 = 0; exp10 < formatCount; ++exp10) {
\r
91 StringBuilder fmt = new StringBuilder();
\r
92 int digits = digitCount;
\r
93 for (int i = 0; i < exp10 && digits > 1; ++i, --digits)
\r
97 if (digits > 0) fmt.append('.');
\r
98 for (; digits > 0; --digits)
\r
100 //System.out.println(fmt.toString());
\r
101 middles[exp10] = new DecimalFormat(fmt.toString(), decimalFormatSymbols);
\r
106 public String engineeringFormat(Object value) {
\r
110 Class<?> clazz = value.getClass();
\r
112 if (clazz == Double.class) {
\r
113 return formatNumber((Double) value);
\r
114 } else if (clazz == Float.class) {
\r
115 return formatNumber((Float)value);
\r
116 } else if (clazz == double[].class) {
\r
117 double[] doubles = (double[])value;
\r
118 StringBuilder b = new StringBuilder();
\r
120 boolean first = true;
\r
121 for (double d : doubles) {
\r
122 if(!first) b.append(",");
\r
123 b.append(formatNumber(d));
\r
127 return b.toString();
\r
128 } else if (clazz == float[].class) {
\r
129 float[] floats = (float[])value;
\r
130 StringBuilder b = new StringBuilder();
\r
132 boolean first = true;
\r
133 for (float f : floats) {
\r
134 if(!first) b.append(",");
\r
135 b.append(formatNumber(f));
\r
139 return b.toString();
\r
140 } else if (clazz == int[].class) {
\r
141 int[] ints = (int[])value;
\r
142 StringBuilder b = new StringBuilder();
\r
144 boolean first = true;
\r
145 for (int d : ints) {
\r
146 if(!first) b.append(",");
\r
151 return b.toString();
\r
152 } else if (clazz == String.class) {
\r
153 return (String) value;
\r
155 return value.toString();
\r
159 public String formatNumber(float v) {
\r
160 if (Float.isInfinite(v)) {
\r
161 return (v == Float.POSITIVE_INFINITY) ? "\u221E" : "-\u221E";
\r
162 } else if (Float.isNaN(v)) {
\r
165 float abs = Math.abs(v);
\r
166 if (abs < 1.0f && abs >= (float)lowLimit) {
\r
167 return flow.format(v);
\r
168 } else if (abs >= 1.0f && abs < (float)highLimit) {
\r
169 double exp = Math.log10(abs);
\r
170 int expi = (int) Math.floor(exp);
\r
171 // System.out.println("format(" + v + ")");
\r
172 // System.out.println("exp: " + exp);
\r
173 // System.out.println("expi: " + expi);
\r
174 if (expi < fmiddles.length) {
\r
175 return fmiddles[expi].format(v);
\r
178 return postprocess( fhigh.format(v) );
\r
182 public String formatNumber(double v) {
\r
183 if (Double.isInfinite(v)) {
\r
184 return (v == Double.POSITIVE_INFINITY) ? "\u221E" : "-\u221E";
\r
185 } else if (Double.isNaN(v)) {
\r
188 double abs = Math.abs(v);
\r
189 if (abs < 1.0 && abs >= lowLimit) {
\r
190 return dlow.format(v);
\r
191 } else if (abs >= 1.0 && abs < highLimit) {
\r
192 double exp = Math.log10(abs);
\r
193 int expi = (int) Math.floor(exp);
\r
194 // System.out.println("format(" + v + ")");
\r
195 // System.out.println("exp: " + exp);
\r
196 // System.out.println("expi: " + expi);
\r
197 if (expi < dmiddles.length) {
\r
198 return dmiddles[expi].format(v);
\r
201 return postprocess( dhigh.format(v) );
\r
205 private static String postprocess(String s) {
\r
206 if (s.endsWith("E0"))
\r
207 return s.substring(0, s.length() - 2);
\r
208 return s.replace('E', 'e');
\r
211 public static String formatNumberLocale(Object num, int minPrecision, int maxPrecision, String languageTag) {
\r
212 NumberFormat format = NumberFormat.getNumberInstance(Locale.forLanguageTag(languageTag));
\r
213 format.setMaximumFractionDigits(maxPrecision);
\r
214 format.setMinimumFractionDigits(minPrecision);
\r
215 if (num instanceof java.lang.Number) {
\r
216 double doubleValue = ((java.lang.Number)num).doubleValue();
\r
217 if(Double.isFinite(doubleValue))
\r
218 return format.format(doubleValue);
\r
219 else if(Double.isNaN(doubleValue)) return "NaN";
\r
220 else if(Double.isInfinite(doubleValue)) return "\u221e";
\r
222 throw new NumberFormatException("Number " + num + ", instanceOf " + num.getClass().getName());
\r
225 public static void main(String[] args) {
\r
226 FormattingUtil fu = new FormattingUtil(7, 15);
\r
227 System.out.println("=== DOUBLE ===");
\r
228 System.out.println(fu.formatNumber(123e-3));
\r
229 System.out.println(fu.formatNumber(-123e-3));
\r
230 System.out.println(fu.formatNumber(Double.POSITIVE_INFINITY));
\r
231 System.out.println(fu.formatNumber(Double.NEGATIVE_INFINITY));
\r
232 System.out.println(fu.formatNumber(Double.NaN));
\r
233 System.out.println(fu.formatNumber(0));
\r
234 System.out.println(fu.formatNumber(0.25));
\r
235 System.out.println(fu.formatNumber(0.1));
\r
236 System.out.println(fu.formatNumber(1));
\r
237 System.out.println(fu.formatNumber(-0.25));
\r
238 System.out.println(fu.formatNumber(-0.1));
\r
239 System.out.println(fu.formatNumber(-1));
\r
240 System.out.println(fu.formatNumber(0.9999));
\r
241 System.out.println(fu.formatNumber(0.0999999999999999999));
\r
242 System.out.println(fu.formatNumber(0.0099999999999999999999));
\r
243 System.out.println(fu.formatNumber(0.004541234));
\r
244 System.out.println(fu.formatNumber(0.00099999999999999999999));
\r
245 System.out.println(fu.formatNumber(0.000099999999999999999999));
\r
246 System.out.println(fu.formatNumber(0.0000099999999999999999999));
\r
247 System.out.println(fu.formatNumber(0.00000099999999999999999999));
\r
248 System.out.println(fu.formatNumber(-0.9999));
\r
249 System.out.println(fu.formatNumber(-0.0999999999999999999));
\r
250 System.out.println(fu.formatNumber(-0.0099999999999999999999));
\r
251 System.out.println(fu.formatNumber(-0.00099999999999999999999));
\r
252 System.out.println(fu.formatNumber(-0.000099999999999999999999));
\r
253 System.out.println(fu.formatNumber(1.234567891));
\r
254 System.out.println(fu.formatNumber(12.34567891));
\r
255 System.out.println(fu.formatNumber(123.4567891));
\r
256 System.out.println(fu.formatNumber(1234.567891));
\r
257 System.out.println(fu.formatNumber(12345.67891));
\r
258 System.out.println(fu.formatNumber(123456.7891));
\r
259 System.out.println(fu.formatNumber(1234567.891));
\r
260 System.out.println(fu.formatNumber(1234567.8912345678));
\r
261 System.out.println(fu.formatNumber(12345678.912345678));
\r
262 System.out.println(fu.formatNumber(123456789.12345678));
\r
263 System.out.println(fu.formatNumber(1234567891.2345678));
\r
264 System.out.println(fu.formatNumber(12345678912.345678));
\r
265 System.out.println(fu.formatNumber(100.0000000000000));
\r
266 System.out.println(fu.formatNumber(100000.0000000000));
\r
267 System.out.println(fu.formatNumber(1000000000.000000));
\r
268 System.out.println(fu.formatNumber(100000000000.0000));
\r
269 System.out.println(fu.formatNumber(10000000000000.00));
\r
270 System.out.println(fu.formatNumber(999999.99999999999999));
\r
271 System.out.println(fu.formatNumber(999999.9999999999999));
\r
272 System.out.println(fu.formatNumber(999999.999999999999));
\r
273 System.out.println(fu.formatNumber(999999.99999999999));
\r
274 System.out.println(fu.formatNumber(999999.9999999999));
\r
275 System.out.println(fu.formatNumber(999999.999999999));
\r
276 System.out.println(fu.formatNumber(999999.99999999));
\r
277 System.out.println(fu.formatNumber(999999.9999999));
\r
278 System.out.println(fu.formatNumber(999999.999999));
\r
279 System.out.println(fu.formatNumber(999999.99999));
\r
280 System.out.println(fu.formatNumber(999999.9999));
\r
281 System.out.println(fu.formatNumber(999999.999));
\r
282 System.out.println(fu.formatNumber(999999.99));
\r
283 System.out.println(fu.formatNumber(999999.9));
\r
284 System.out.println(fu.formatNumber(999999));
\r
286 System.out.println("=== FLOAT ===");
\r
287 System.out.println(fu.formatNumber(123e-3f));
\r
288 System.out.println(fu.formatNumber(-123e-3f));
\r
289 System.out.println(fu.formatNumber(Float.POSITIVE_INFINITY));
\r
290 System.out.println(fu.formatNumber(Float.NEGATIVE_INFINITY));
\r
291 System.out.println(fu.formatNumber(Float.NaN));
\r
292 System.out.println(fu.formatNumber(0f));
\r
293 System.out.println(fu.formatNumber(0.25f));
\r
294 System.out.println(fu.formatNumber(0.1f));
\r
295 System.out.println(fu.formatNumber(1f));
\r
296 System.out.println(fu.formatNumber(-0.25f));
\r
297 System.out.println(fu.formatNumber(-0.1f));
\r
298 System.out.println(fu.formatNumber(-1f));
\r
299 System.out.println(fu.formatNumber(0.9999f));
\r
300 System.out.println(fu.formatNumber(0.0999999999999999999f));
\r
301 System.out.println(fu.formatNumber(0.0099999999999999999999f));
\r
302 System.out.println(fu.formatNumber(0.004541234f));
\r
303 System.out.println(fu.formatNumber(0.00099999999999999999999f));
\r
304 System.out.println(fu.formatNumber(0.000099999999999999999999f));
\r
305 System.out.println(fu.formatNumber(0.0000099999999999999999999f));
\r
306 System.out.println(fu.formatNumber(0.00000099999999999999999999f));
\r
307 System.out.println(fu.formatNumber(-0.9999f));
\r
308 System.out.println(fu.formatNumber(-0.0999999999999999999f));
\r
309 System.out.println(fu.formatNumber(-0.0099999999999999999999f));
\r
310 System.out.println(fu.formatNumber(-0.00099999999999999999999f));
\r
311 System.out.println(fu.formatNumber(-0.000099999999999999999999f));
\r
312 System.out.println(fu.formatNumber(1.234567891f));
\r
313 System.out.println(fu.formatNumber(12.34567891f));
\r
314 System.out.println(fu.formatNumber(123.4567891f));
\r
315 System.out.println(fu.formatNumber(1234.567891f));
\r
316 System.out.println(fu.formatNumber(12345.67891f));
\r
317 System.out.println(fu.formatNumber(123456.7891f));
\r
318 System.out.println(fu.formatNumber(1234567.891f));
\r
319 System.out.println(fu.formatNumber(1234567.8912345678f));
\r
320 System.out.println(fu.formatNumber(12345678.912345678f));
\r
321 System.out.println(fu.formatNumber(123456789.12345678f));
\r
322 System.out.println(fu.formatNumber(1234567891.2345678f));
\r
323 System.out.println(fu.formatNumber(12345678912.345678f));
\r
324 System.out.println(fu.formatNumber(100.0000000000000f));
\r
325 System.out.println(fu.formatNumber(100000.0000000000f));
\r
326 System.out.println(fu.formatNumber(1000000000.000000f));
\r
327 System.out.println(fu.formatNumber(100000000000.0000f));
\r
328 System.out.println(fu.formatNumber(10000000000000.00f));
\r
329 System.out.println(fu.formatNumber(999999.99999999999999f));
\r
330 System.out.println(fu.formatNumber(999999.9999999999999f));
\r
331 System.out.println(fu.formatNumber(999999.999999999999f));
\r
332 System.out.println(fu.formatNumber(999999.99999999999f));
\r
333 System.out.println(fu.formatNumber(999999.9999999999f));
\r
334 System.out.println(fu.formatNumber(999999.999999999f));
\r
335 System.out.println(fu.formatNumber(999999.99999999f));
\r
336 System.out.println(fu.formatNumber(999999.9999999f));
\r
337 System.out.println(fu.formatNumber(999999.999999f));
\r
338 System.out.println(fu.formatNumber(999999.99999f));
\r
339 System.out.println(fu.formatNumber(999999.9999f));
\r
340 System.out.println(fu.formatNumber(999999.999f));
\r
341 System.out.println(fu.formatNumber(999999.99f));
\r
342 System.out.println(fu.formatNumber(999999.9f));
\r
343 System.out.println(fu.formatNumber(999999f));
\r