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
33import java.math.BigDecimal;
34import java.math.BigInteger;
35import java.text.NumberFormat;
36import java.text.DecimalFormat;
37import java.math.RoundingMode;
38import java.util.Locale;
39
40public class TieRoundingTest {
41
42    static int testCounter = 0;
43    static int errorCounter = 0;
44    static boolean allPassed = true;
45
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
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
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
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