1 /*
2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /* @test
25  *
26  * @bug 7131459 8039915
27  * @summary test various situations of NumberFormat rounding when close to tie
28  * @author Olivier Lagneau
29  * @run main TieRoundingTest
30  *
31  */
32 
33 import java.math.BigDecimal;
34 import java.math.BigInteger;
35 import java.text.NumberFormat;
36 import java.text.DecimalFormat;
37 import java.math.RoundingMode;
38 import java.util.Locale;
39 
40 public class TieRoundingTest {
41 
42     static int testCounter = 0;
43     static int errorCounter = 0;
44     static boolean allPassed = true;
45 
formatOutputTestDouble(NumberFormat nf, double doubleToTest, String tiePosition, String inputDigits, String expectedOutput)46     static void formatOutputTestDouble(NumberFormat nf,
47                                        double doubleToTest,
48                                        String tiePosition,
49                                        String inputDigits,
50                                        String expectedOutput) {
51 
52         int mfd = nf.getMaximumFractionDigits();
53         RoundingMode rm = nf.getRoundingMode();
54         String result = nf.format(doubleToTest);
55 
56         if (!result.equals(expectedOutput)) {
57             System.out.println();
58             System.out.println("========================================");
59             System.out.println("***Failure : error formatting value from string : " +
60                                inputDigits);
61             System.out.println("NumberFormat pattern is  : " +
62                                ((DecimalFormat ) nf).toPattern());
63             System.out.println("Maximum number of fractional digits : " + mfd);
64             System.out.println("Fractional rounding digit : " + (mfd + 1));
65             System.out.println("Position of value relative to tie : " + tiePosition);
66             System.out.println("Rounding Mode : " + rm);
67             System.out.println("BigDecimal output : " +
68                                new BigDecimal(doubleToTest).toString());
69             System.out.println("FloatingDecimal output : " + doubleToTest);
70             System.out.println(
71                "Error. Formatted result different from expected." +
72                "\nExpected output is : \"" + expectedOutput + "\"" +
73                "\nFormated output is : \"" + result + "\"");
74             System.out.println("========================================");
75             System.out.println();
76 
77             errorCounter++;
78             allPassed = false;
79         } else {
80             testCounter++;
81             System.out.println("\nSuccess for double value : " + doubleToTest + " :");
82             System.out.println(" Input digits :" + inputDigits +
83                                ", BigDecimal value : " +
84                                new BigDecimal(doubleToTest).toString());
85             System.out.print(" Rounding mode: " + rm);
86             System.out.print(", fract digits : " + mfd);
87             System.out.print(", position : " + tiePosition + " tie");
88             System.out.print(", result : " + result);
89             System.out.println(", expected : " + expectedOutput);
90         }
91     }
92 
formatOutputTestLong(NumberFormat nf, long longToTest, String tiePosition, String inputDigits, String expectedOutput)93     static void formatOutputTestLong(NumberFormat nf,
94                                      long longToTest,
95                                      String tiePosition,
96                                      String inputDigits,
97                                      String expectedOutput) {
98 
99         int mfd = nf.getMaximumFractionDigits();
100         RoundingMode rm = nf.getRoundingMode();
101         String result = nf.format(longToTest);
102 
103         if (!result.equals(expectedOutput)) {
104             System.out.println();
105             System.out.println("========================================");
106             System.out.println("***Failure : error formatting value from string : " +
107                                inputDigits);
108             System.out.println("NumberFormat pattern is  : " +
109                                ((DecimalFormat ) nf).toPattern());
110             System.out.println("Maximum number of fractional digits : " + mfd);
111             System.out.println("Fractional rounding digit : " + (mfd + 1));
112             System.out.println("Position of value relative to tie : " + tiePosition);
113             System.out.println("Rounding Mode : " + rm);
114             System.out.println(
115                "Error. Formatted result different from expected." +
116                "\nExpected output is : \"" + expectedOutput + "\"" +
117                "\nFormated output is : \"" + result + "\"");
118             System.out.println("========================================");
119             System.out.println();
120 
121             errorCounter++;
122             allPassed = false;
123         } else {
124             testCounter++;
125             System.out.print("Success. Long input :" + inputDigits);
126             System.out.print(", rounding : " + rm);
127             System.out.print(", fract digits : " + mfd);
128             System.out.print(", tie position : " + tiePosition);
129             System.out.println(", expected : " + expectedOutput);
130 
131         }
132     }
133 
formatOutputTestObject(NumberFormat nf, Object someNumber, String tiePosition, String inputDigits, String expectedOutput)134     static void formatOutputTestObject(NumberFormat nf,
135                                        Object someNumber,
136                                        String tiePosition,
137                                        String inputDigits,
138                                        String expectedOutput) {
139 
140         int mfd = nf.getMaximumFractionDigits();
141         RoundingMode rm = nf.getRoundingMode();
142         String result = nf.format(someNumber);
143 
144         if (!result.equals(expectedOutput)) {
145             System.out.println();
146             System.out.println("========================================");
147             System.out.println("***Failure : error formatting value from string : " +
148                                inputDigits);
149             System.out.println("NumberFormat pattern is  : " +
150                                ((DecimalFormat ) nf).toPattern());
151             System.out.println("Maximum number of fractional digits : " + mfd);
152             System.out.println("Fractional rounding digit : " + (mfd + 1));
153             System.out.println("Position of value relative to tie : " + tiePosition);
154             System.out.println("Rounding Mode : " + rm);
155             System.out.println("Number self output representation: " + someNumber);
156             System.out.println(
157                "Error. Formatted result different from expected." +
158                "\nExpected output is : \"" + expectedOutput + "\"" +
159                "\nFormated output is : \"" + result + "\"");
160             System.out.println("========================================");
161             System.out.println();
162 
163             errorCounter++;
164             allPassed = false;
165         } else {
166             testCounter++;
167             System.out.print("Success. Number input :" + inputDigits);
168             System.out.print(", rounding : " + rm);
169             System.out.print(", fract digits : " + mfd);
170             System.out.print(", tie position : " + tiePosition);
171             System.out.println(", expected : " + expectedOutput);
172         }
173     }
174 
main(String[] args)175     public static void main(String[] args) {
176 
177         // The 3 HALF_* rounding modes are impacted by bugs 7131459, 8039915.
178         // So we do not test the other rounding modes.
179         RoundingMode[] roundingModes = {
180             RoundingMode.HALF_DOWN,
181             RoundingMode.HALF_EVEN,
182             RoundingMode.HALF_UP
183         };
184 
185         // Precise the relative position of input value against its closest tie.
186         // The double values tested below for 3 and 5 fractional digits must follow
187         // this scheme (position toward tie).
188         String[] tieRelativePositions = {
189             "below", "exact", "above",
190             "below", "exact", "above",
191             "below", "exact", "above",
192             "below", "above", "above",
193             "below", "below", "above",
194             "below", "exact", "above"
195         };
196 
197         // =============== Testing double (and thus float) value cases =========
198 
199         System.out.println("\n===== testing 3 digits rounding position =====");
200         double[] values3FractDigits = {
201             // unimpacting values close to tie, with less than 3 input fract digits
202             1.115d, 1.125d, 1.135d,
203             // HALF_* impacting close to tie values covering all 6 tie cases
204             0.3115d, 0.3125d, 0.3135d,
205             0.6865d, 0.6875d, 0.6885d,
206             // specific HALF_UP close to tie values
207             0.3124d, 0.3126d, 0.3128d,
208             // specific HALF_DOWN close to tie values
209             0.6864d, 0.6865d, 0.6868d,
210             // unimpacting values close to tie, with more than 3 input fract digits
211             1.46885d, 2.46875d, 1.46865d
212         };
213 
214         String[] inputs3FractDigits = {
215             "1.115d", "1.125d", "1.135d",
216             "0.3115d", "0.3125d", "0.3135d",
217             "0.6865d", "0.6875d", "0.6885d",
218             "0.3124d", "0.3126d", "0.3128d",
219             "0.6864d", "0.6865d", "0.6868d",
220             "1.46885d", "2.46875d", "1.46865d"
221         };
222 
223         String[][] expected3FractDigits = {
224             {"1.115", "1.125", "1.135",
225              "0.311", "0.312", "0.314",
226              "0.686", "0.687", "0.689",
227              "0.312", "0.313", "0.313",
228              "0.686", "0.686", "0.687",
229              "1.469", "2.469", "1.469"
230             },
231             {"1.115", "1.125", "1.135",
232              "0.311", "0.312", "0.314",
233              "0.686", "0.688", "0.689",
234              "0.312", "0.313", "0.313",
235              "0.686", "0.686", "0.687",
236              "1.469", "2.469", "1.469"
237             },
238             {"1.115", "1.125", "1.135",
239              "0.311", "0.313", "0.314",
240              "0.686", "0.688", "0.689",
241              "0.312", "0.313", "0.313",
242              "0.686", "0.686", "0.687",
243              "1.469", "2.469", "1.469"
244             },
245         };
246 
247 
248         for (int r = 0; r < roundingModes.length; r++) {
249             NumberFormat dfDefault = NumberFormat.getInstance(Locale.US);
250             RoundingMode rmode = roundingModes[r];
251             dfDefault.setRoundingMode(rmode);
252             System.out.println("\n----- Now checking " + rmode +
253                                " rounding mode -----");
254 
255             for (int i = 0; i < values3FractDigits.length; i++) {
256                 double d = values3FractDigits[i];
257                 String tiePosition = tieRelativePositions[i];
258                 String input = inputs3FractDigits[i];
259                 String expected = expected3FractDigits[r][i];
260 
261                 formatOutputTestDouble(dfDefault, d, tiePosition, input, expected);
262             }
263         }
264 
265         System.out.println("\n===== testing 5 digits rounding position =====");
266         double[] values5FractDigits = {
267             // unimpacting values close to tie, with less than 5 input fract digits
268             1.3135d, 1.3125d, 1.3115d,
269             // HALF_* impacting values close to tie, covering all 6 cases
270             1.328115d, 1.328125d, 1.328135d,
271             1.796865d, 1.796875d, 1.796885d,
272             // specific HALF_UP close to tie values
273             1.328124d, 1.798876d, 1.796889d,
274             // specific HALF_DOWN close to tie values
275             1.328114d, 1.796865d, 1.328138d,
276             // unimpacting values close to tie, with more than 5 input fract digits
277             1.3281149999999d, 1.75390625d, 1.7968750000001d
278         };
279 
280         String[] inputs5FractDigits = {
281             "1.3135d", "1.3125d", "1.3115d",
282             "1.328115d", "1.328125d", "1.328135d",
283             "1.796865d", "1.796875d", "1.796885d",
284             "1.328124d", "1.798876d", "1.796889d",
285             "1.328114d", "1.796865d", "1.328138d",
286             "1.3281149999999d", "1.75390625d", "1.7968750000001d"
287         };
288 
289         String[][] expected5FractDigits = {
290             {"1.3135", "1.3125", "1.3115",
291              "1.32811", "1.32812", "1.32814",
292              "1.79686", "1.79687", "1.79689",
293              "1.32812", "1.79888", "1.79689",
294              "1.32811", "1.79686", "1.32814",
295              "1.32811", "1.75391", "1.79688"
296             },
297             {"1.3135", "1.3125", "1.3115",
298              "1.32811", "1.32812", "1.32814",
299              "1.79686", "1.79688", "1.79689",
300              "1.32812", "1.79888", "1.79689",
301              "1.32811", "1.79686", "1.32814",
302              "1.32811", "1.75391", "1.79688"
303             },
304             {"1.3135", "1.3125", "1.3115",
305              "1.32811", "1.32813", "1.32814",
306              "1.79686", "1.79688", "1.79689",
307              "1.32812", "1.79888", "1.79689",
308              "1.32811", "1.79686", "1.32814",
309              "1.32811", "1.75391", "1.79688"
310             }
311         };
312 
313 
314         for (int r = 0; r < roundingModes.length; r++) {
315             DecimalFormat df5 = (DecimalFormat) NumberFormat.getInstance(Locale.US);
316             RoundingMode rmode = roundingModes[r];
317             df5.setRoundingMode(rmode);
318             System.out.println("\n----- Now checking " + rmode +
319                                " rounding mode -----");
320             df5.applyPattern("#,###.#####");
321 
322             for (int i = 0; i < values5FractDigits.length; i++) {
323                 double d = values5FractDigits[i];
324                 String tiePosition = tieRelativePositions[i];
325                 String input = inputs5FractDigits[i];
326                 String expected = expected5FractDigits[r][i];
327 
328                 formatOutputTestDouble(df5, d, tiePosition, input, expected);
329             }
330         }
331 
332         // ==================== Testing long value cases ====================
333 
334         System.out.println("\n===== testing long values =====");
335         long l = 123456789012345L;
336         DecimalFormat dfLong = (DecimalFormat) NumberFormat.getInstance(Locale.US);
337         String tiePosition = "exact";
338         String input = "123456789012345L";
339         String expected = "123,456,789,012,345";
340         String result = dfLong.format(l);
341         formatOutputTestLong(dfLong, l, tiePosition, input, expected);
342 
343         dfLong.applyPattern("0.###E0");
344         expected = "1.235E14";
345         formatOutputTestLong(dfLong, l, tiePosition, input, expected);
346 
347         l = 123450000000000L;
348         input = "123450000000000L";
349         expected = "1.234E14";
350         formatOutputTestLong(dfLong, l, tiePosition, input, expected);
351 
352         l = 987750000000000L;
353         input = "987750000000000L";
354         expected = "9.878E14";
355         formatOutputTestLong(dfLong, l, tiePosition, input, expected);
356 
357         dfLong.applyPattern("#,###.0E0");
358         l = 987755000000000L;
359         input = "987755000000000L";
360         expected = "987.76E12";
361 
362         formatOutputTestLong(dfLong, l, tiePosition, input, expected);
363 
364 
365         // ================= Testing BigInteger value cases =================
366 
367         System.out.println("\n===== testing BigInteger values =====");
368         String stringValue = "12345678901234567890123456789012345";
369         BigInteger bi = new BigInteger(stringValue);
370         DecimalFormat dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
371         tiePosition = "exact";
372         input = stringValue;
373         expected = "12,345,678,901,234,567,890,123,456,789,012,345";
374         formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
375 
376         dfBig.applyPattern("0.###E0");
377         expected = "1.235E34";
378         formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
379 
380         stringValue = "12345000000000000000000000000000000";
381         input = stringValue;
382         bi = new BigInteger(stringValue);
383         expected = "1.234E34";
384         formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
385 
386         stringValue = "12345000000000000000000000000000001";
387         input = stringValue;
388         bi = new BigInteger(stringValue);
389         expected = "1.235E34";
390         formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
391 
392         stringValue = "98755000000000000000000000000000000";
393         input = stringValue;
394         bi = new BigInteger(stringValue);
395         expected = "9.876E34";
396         formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
397 
398         dfLong.applyPattern("#,###.0E0");
399         stringValue = "98775500000000000000000000000000000";
400         input = stringValue;
401         expected = "987.76E34";
402 
403         // =============== Testing BigDecimal value cases ================
404 
405         System.out.println("\n===== testing BigDecimal values =====");
406         dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
407 
408         stringValue = "0.68850000000000000088817841970012523233890533447265625";
409         BigDecimal bd = new BigDecimal(stringValue);
410         tiePosition = "exact";
411         input = stringValue;
412         expected = "0.689";
413         formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
414 
415         stringValue = "0.31149999999999999911182158029987476766109466552734375";
416         bd = new BigDecimal(stringValue);
417         dfBig.applyPattern("#,##0.####");
418         tiePosition = "exact";
419         input = stringValue;
420         expected = "0.3115";
421         formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
422 
423         // ==================== Printing results and exiting ===================
424 
425         System.out.println();
426         System.out.println("==> " + testCounter + " tests passed successfully");
427         System.out.println("==> " + errorCounter + " tests failed");
428 
429         System.out.println();
430         if (allPassed) {
431             System.out.println(
432                 "Success in formating all the values with the given parameters");
433         } else {
434             String s = "Test failed with " + errorCounter + " formating error(s).";
435             System.out.println(s);
436             throw new RuntimeException(s);
437         }
438     }
439 }
440