changeset 6384:bc1f16f5566f

7131459: [Fmt-De] DecimalFormat produces wrong format() results when close to a tie Reviewed-by: darcy Contributed-by: olivier.lagneau@oracle.com
author darcy
date Fri, 11 Jan 2013 15:39:08 -0800
parents 7da291690aa0
children 8009c7e3899e
files src/share/classes/java/text/DigitList.java src/share/classes/sun/misc/FloatingDecimal.java test/java/text/Format/DecimalFormat/TieRoundingTest.java
diffstat 3 files changed, 568 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/text/DigitList.java	Fri Jan 11 20:19:55 2013 +0000
+++ b/src/share/classes/java/text/DigitList.java	Fri Jan 11 15:39:08 2013 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,7 @@
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
+import sun.misc.FloatingDecimal;
 
 /**
  * Digit List. Private to DecimalFormat.
@@ -62,7 +63,7 @@
  * derived by placing all the digits of the list to the right of the
  * decimal point, by 10^exponent.
  *
- * @see  java.util.Locale
+ * @see  Locale
  * @see  Format
  * @see  NumberFormat
  * @see  DecimalFormat
@@ -286,14 +287,27 @@
      * fractional digits to be converted.  If false, total digits.
      */
     final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
-        set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
+
+        FloatingDecimal fd = new FloatingDecimal(source);
+        boolean hasBeenRoundedUp = fd.digitsRoundedUp();
+        boolean allDecimalDigits = fd.decimalDigitsExact();
+        String digitsString = fd.toJavaFormatString();
+
+        set(isNegative, digitsString,
+            hasBeenRoundedUp, allDecimalDigits,
+            maximumDigits, fixedPoint);
     }
 
     /**
      * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
      * DDDDDE+/-DDDDD.
+     * @param roundedUp Boolean value indicating if the s digits were rounded-up.
+     * @param allDecimalDigits Boolean value indicating if the digits in s are
+     * an exact decimal representation of the double that was passed.
      */
-    final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
+    final void set(boolean isNegative, String s,
+                   boolean roundedUp, boolean allDecimalDigits,
+                   int maximumDigits, boolean fixedPoint) {
         this.isNegative = isNegative;
         int len = s.length();
         char[] source = getDataChars(len);
@@ -346,7 +360,7 @@
             } else if (-decimalAt == maximumDigits) {
                 // If we round 0.0009 to 3 fractional digits, then we have to
                 // create a new one digit in the least significant location.
-                if (shouldRoundUp(0)) {
+                if (shouldRoundUp(0, roundedUp, allDecimalDigits)) {
                     count = 1;
                     ++decimalAt;
                     digits[0] = '1';
@@ -365,19 +379,26 @@
 
         // Eliminate digits beyond maximum digits to be displayed.
         // Round up if appropriate.
-        round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
+        round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits,
+              roundedUp, allDecimalDigits);
     }
 
     /**
      * Round the representation to the given number of digits.
      * @param maximumDigits The maximum number of digits to be shown.
+     * @param alreadyRounded Boolean indicating if rounding up already happened.
+     * @param allDecimalDigits Boolean indicating if the digits provide an exact
+     * representation of the value.
+     *
      * Upon return, count will be less than or equal to maximumDigits.
      */
-    private final void round(int maximumDigits) {
+    private final void round(int maximumDigits,
+                             boolean alreadyRounded,
+                             boolean allDecimalDigits) {
         // Eliminate digits beyond maximum digits to be displayed.
         // Round up if appropriate.
         if (maximumDigits >= 0 && maximumDigits < count) {
-            if (shouldRoundUp(maximumDigits)) {
+            if (shouldRoundUp(maximumDigits, alreadyRounded, allDecimalDigits)) {
                 // Rounding up involved incrementing digits from LSD to MSD.
                 // In most cases this is simple, but in a worst case situation
                 // (9999..99) we have to adjust the decimalAt value.
@@ -423,8 +444,56 @@
      * @return true if digit <code>maximumDigits-1</code> should be
      * incremented
      */
-    private boolean shouldRoundUp(int maximumDigits) {
+    private boolean shouldRoundUp(int maximumDigits,
+                                  boolean alreadyRounded,
+                                  boolean allDecimalDigits) {
         if (maximumDigits < count) {
+            /*
+             * To avoid erroneous double-rounding or truncation when converting
+             * a binary double value to text, information about the exactness
+             * of the conversion result in FloatingDecimal, as well as any
+             * rounding done, is needed in this class.
+             *
+             * - For the  HALF_DOWN, HALF_EVEN, HALF_UP rounding rules below:
+             *   In the case of formating float or double, We must take into
+             *   account what FloatingDecimal has done in the binary to decimal
+             *   conversion.
+             *
+             *   Considering the tie cases, FloatingDecimal may round-up the
+             *   value (returning decimal digits equal to tie when it is below),
+             *   or "truncate" the value to the tie while value is above it,
+             *   or provide the exact decimal digits when the binary value can be
+             *   converted exactly to its decimal representation given formating
+             *   rules of FloatingDecimal ( we have thus an exact decimal
+             *   representation of the binary value).
+             *
+             *   - If the double binary value was converted exactly as a decimal
+             *     value, then DigitList code must apply the expected rounding
+             *     rule.
+             *
+             *   - If FloatingDecimal already rounded up the decimal value,
+             *     DigitList should neither round up the value again in any of
+             *     the three rounding modes above.
+             *
+             *   - If FloatingDecimal has truncated the decimal value to
+             *     an ending '5' digit, DigitList should round up the value in
+             *     all of the three rounding modes above.
+             *
+             *
+             *   This has to be considered only if digit at maximumDigits index
+             *   is exactly the last one in the set of digits, otherwise there are
+             *   remaining digits after that position and we dont have to consider
+             *   what FloatingDecimal did.
+             *
+             * - Other rounding modes are not impacted by these tie cases.
+             *
+             * - For other numbers that are always converted to exact digits
+             *   (like BigInteger, Long, ...), the passed alreadyRounded boolean
+             *   have to be  set to false, and allDecimalDigits has to be set to
+             *   true in the upper DigitList call stack, providing the right state
+             *   for those situations..
+             */
+
             switch(roundingMode) {
             case UP:
                 for (int i=maximumDigits; i<count; ++i) {
@@ -451,6 +520,13 @@
                 break;
             case HALF_UP:
                 if (digits[maximumDigits] >= '5') {
+                    // We should not round up if the rounding digits position is
+                    // exactly the last index and if digits were already rounded.
+                    if ((maximumDigits == (count - 1)) &&
+                        (alreadyRounded))
+                        return false;
+
+                    // Value was exactly at or was above tie. We must round up.
                     return true;
                 }
                 break;
@@ -458,6 +534,21 @@
                 if (digits[maximumDigits] > '5') {
                     return true;
                 } else if (digits[maximumDigits] == '5' ) {
+                    if (maximumDigits == (count - 1)) {
+                        // The rounding position is exactly the last index.
+                        if (allDecimalDigits || alreadyRounded)
+                            /* FloatingDecimal rounded up (value was below tie),
+                             * or provided the exact list of digits (value was
+                             * an exact tie). We should not round up, following
+                             * the HALF_DOWN rounding rule.
+                             */
+                            return false;
+                        else
+                            // Value was above the tie, we must round up.
+                            return true;
+                    }
+
+                    // We must round up if it gives a non null digit after '5'.
                     for (int i=maximumDigits+1; i<count; ++i) {
                         if (digits[i] != '0') {
                             return true;
@@ -470,12 +561,32 @@
                 if (digits[maximumDigits] > '5') {
                     return true;
                 } else if (digits[maximumDigits] == '5' ) {
-                    for (int i=maximumDigits+1; i<count; ++i) {
-                        if (digits[i] != '0') {
+                    if (maximumDigits == (count - 1)) {
+                        // the rounding position is exactly the last index :
+                        if (alreadyRounded)
+                            // If FloatingDecimal rounded up (value was below tie),
+                            // then we should not round up again.
+                            return false;
+
+                        if (!allDecimalDigits)
+                            // Otherwise if the digits dont represent exact value,
+                            // value was above tie and FloatingDecimal truncated
+                            // digits to tie. We must round up.
                             return true;
+                        else {
+                            // This is an exact tie value, and FloatingDecimal
+                            // provided all of the exact digits. We thus apply
+                            // HALF_EVEN rounding rule.
+                            return ((maximumDigits > 0) &&
+                                    (digits[maximumDigits-1] % 2 != 0));
+                        }
+                    } else {
+                        // Rounds up if it gives a non null digit after '5'
+                        for (int i=maximumDigits+1; i<count; ++i) {
+                            if (digits[i] != '0')
+                                return true;
                         }
                     }
-                    return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
                 }
                 break;
             case UNNECESSARY:
@@ -542,7 +653,7 @@
             count = right - left + 1;
             System.arraycopy(digits, left, digits, 0, count);
         }
-        if (maximumDigits > 0) round(maximumDigits);
+        if (maximumDigits > 0) round(maximumDigits, false, true);
     }
 
     /**
@@ -559,7 +670,9 @@
         String s = source.toString();
         extendDigits(s.length());
 
-        set(isNegative, s, maximumDigits, fixedPoint);
+        set(isNegative, s,
+            false, true,
+            maximumDigits, fixedPoint);
     }
 
     /**
@@ -584,7 +697,7 @@
         count = right + 1;
 
         if (maximumDigits > 0) {
-            round(maximumDigits);
+            round(maximumDigits, false, true);
         }
     }
 
--- a/src/share/classes/sun/misc/FloatingDecimal.java	Fri Jan 11 20:19:55 2013 +0000
+++ b/src/share/classes/sun/misc/FloatingDecimal.java	Fri Jan 11 15:39:08 2013 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,19 @@
     boolean     fromHex = false;
     int         roundDir = 0; // set by doubleValue
 
+    /*
+     * The fields below provides additional information about the result of
+     * the binary to decimal digits conversion done in dtoa() and roundup()
+     * methods. They are changed if needed by those two methods.
+     */
+
+    // True if the dtoa() binary to decimal conversion was exact.
+    boolean     exactDecimalConversion = false;
+
+    // True if the result of the binary to decimal conversion was rounded-up
+    // at the end of the conversion process, i.e. roundUp() method was called.
+    boolean     decimalDigitsRoundedUp = false;
+
     private     FloatingDecimal( boolean negSign, int decExponent, char []digits, int n,  boolean e )
     {
         isNegative = negSign;
@@ -396,6 +409,11 @@
             // else fall through.
         }
         digits[i] = (char)(q+1);
+        decimalDigitsRoundedUp = true;
+    }
+
+    public boolean digitsRoundedUp() {
+        return decimalDigitsRoundedUp;
     }
 
     /*
@@ -751,6 +769,7 @@
                     digits[ndigit++] = (char)('0' + q);
                 }
                 lowDigitDifference = (b<<1) - tens;
+                exactDecimalConversion  = (b == 0);
             } else {
                 // still good! they're all longs!
                 long b = (fractBits * long5pow[B5] ) << B2;
@@ -804,8 +823,10 @@
                     digits[ndigit++] = (char)('0' + q);
                 }
                 lowDigitDifference = (b<<1) - tens;
+                exactDecimalConversion  = (b == 0);
             }
         } else {
+            FDBigInt ZeroVal = new FDBigInt(0);
             FDBigInt tenSval;
             int  shiftBias;
 
@@ -859,8 +880,10 @@
             if ( high && low ){
                 Bval.lshiftMe(1);
                 lowDigitDifference = Bval.cmp(tenSval);
-            } else
+            } else {
                 lowDigitDifference = 0L; // this here only for flow analysis!
+            }
+            exactDecimalConversion  = (Bval.cmp( ZeroVal ) == 0);
         }
         this.decExponent = decExp+1;
         this.digits = digits;
@@ -883,6 +906,10 @@
         }
     }
 
+    public boolean decimalDigitsExact() {
+        return exactDecimalConversion;
+    }
+
     public String
     toString(){
         // most brain-dead version
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/text/Format/DecimalFormat/TieRoundingTest.java	Fri Jan 11 15:39:08 2013 -0800
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ *
+ * @bug 7131459
+ * @summary test various situations of NumberFormat rounding when close to tie
+ * @author Olivier Lagneau
+ * @run main TieRoundingTest
+ *
+ */
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.NumberFormat;
+import java.text.DecimalFormat;
+import java.math.RoundingMode;
+import java.util.Locale;
+
+public class TieRoundingTest {
+
+    static int testCounter = 0;
+    static int errorCounter = 0;
+    static boolean allPassed = true;
+
+    static void formatOutputTestDouble(NumberFormat nf,
+                                       double doubleToTest,
+                                       String tiePosition,
+                                       String inputDigits,
+                                       String expectedOutput) {
+
+        int mfd = nf.getMaximumFractionDigits();
+        RoundingMode rm = nf.getRoundingMode();
+        String result = nf.format(doubleToTest);
+
+        if (!result.equals(expectedOutput)) {
+            System.out.println();
+            System.out.println("========================================");
+            System.out.println("***Error formatting double value from string : " +
+                               inputDigits);
+            System.out.println("NumberFormat pattern is  : " +
+                               ((DecimalFormat ) nf).toPattern());
+            System.out.println("Maximum number of fractional digits : " + mfd);
+            System.out.println("Fractional rounding digit : " + (mfd + 1));
+            System.out.println("Position of value relative to tie : " + tiePosition);
+            System.out.println("Rounding Mode : " + rm);
+            System.out.println("BigDecimal output : " +
+                               new BigDecimal(doubleToTest).toString());
+            System.out.println("FloatingDecimal output : " + doubleToTest);
+            System.out.println(
+               "Error. Formatted result different from expected." +
+               "\nExpected output is : \"" + expectedOutput + "\"" +
+               "\nFormated output is : \"" + result + "\"");
+            System.out.println("========================================");
+            System.out.println();
+
+            errorCounter++;
+            allPassed = false;
+        } else {
+            testCounter++;
+            System.out.println("\nSuccess for double value : " + doubleToTest + " :");
+            System.out.println(" Input digits :" + inputDigits +
+                               ", BigDecimal value : " +
+                               new BigDecimal(doubleToTest).toString());
+            System.out.print(" Rounding mode: " + rm);
+            System.out.print(", fract digits : " + mfd);
+            System.out.print(", position : " + tiePosition + " tie");
+            System.out.print(", result : " + result);
+            System.out.println(", expected : " + expectedOutput);
+        }
+    }
+
+    static void formatOutputTestLong(NumberFormat nf,
+                                     long longToTest,
+                                     String tiePosition,
+                                     String inputDigits,
+                                     String expectedOutput) {
+
+        int mfd = nf.getMaximumFractionDigits();
+        RoundingMode rm = nf.getRoundingMode();
+        String result = nf.format(longToTest);
+
+        if (!result.equals(expectedOutput)) {
+            System.out.println();
+            System.out.println("========================================");
+            System.out.println("***Error formatting double value from string : " +
+                               inputDigits);
+            System.out.println("NumberFormat pattern is  : " +
+                               ((DecimalFormat ) nf).toPattern());
+            System.out.println("Maximum number of fractional digits : " + mfd);
+            System.out.println("Fractional rounding digit : " + (mfd + 1));
+            System.out.println("Position of value relative to tie : " + tiePosition);
+            System.out.println("Rounding Mode : " + rm);
+            System.out.println(
+               "Error. Formatted result different from expected." +
+               "\nExpected output is : \"" + expectedOutput + "\"" +
+               "\nFormated output is : \"" + result + "\"");
+            System.out.println("========================================");
+            System.out.println();
+
+            errorCounter++;
+            allPassed = false;
+        } else {
+            testCounter++;
+            System.out.print("Success. Long input :" + inputDigits);
+            System.out.print(", rounding : " + rm);
+            System.out.print(", fract digits : " + mfd);
+            System.out.print(", tie position : " + tiePosition);
+            System.out.println(", expected : " + expectedOutput);
+
+        }
+    }
+
+    static void formatOutputTestObject(NumberFormat nf,
+                                       Object someNumber,
+                                       String tiePosition,
+                                       String inputDigits,
+                                       String expectedOutput) {
+
+        int mfd = nf.getMaximumFractionDigits();
+        RoundingMode rm = nf.getRoundingMode();
+        String result = nf.format(someNumber);
+
+        if (!result.equals(expectedOutput)) {
+            System.out.println();
+            System.out.println("========================================");
+            System.out.println("***Error formatting number value from string : " +
+                               inputDigits);
+            System.out.println("NumberFormat pattern is  : " +
+                               ((DecimalFormat ) nf).toPattern());
+            System.out.println("Maximum number of fractional digits : " + mfd);
+            System.out.println("Fractional rounding digit : " + (mfd + 1));
+            System.out.println("Position of value relative to tie : " + tiePosition);
+            System.out.println("Rounding Mode : " + rm);
+            System.out.println("Number self output representation: " + someNumber);
+            System.out.println(
+               "Error. Formatted result different from expected." +
+               "\nExpected output is : \"" + expectedOutput + "\"" +
+               "\nFormated output is : \"" + result + "\"");
+            System.out.println("========================================");
+            System.out.println();
+
+            errorCounter++;
+            allPassed = false;
+        } else {
+            testCounter++;
+            System.out.print("Success. Number input :" + inputDigits);
+            System.out.print(", rounding : " + rm);
+            System.out.print(", fract digits : " + mfd);
+            System.out.print(", tie position : " + tiePosition);
+            System.out.println(", expected : " + expectedOutput);
+        }
+    }
+
+    public static void main(String[] args) {
+
+        // Only the 3 rounding modes below may be impacted by bug 7131459.
+        // So we do not test the other rounding modes.
+        RoundingMode[] roundingModes = {
+            RoundingMode.HALF_DOWN,
+            RoundingMode.HALF_EVEN,
+            RoundingMode.HALF_UP
+        };
+
+        // Precise the relative position of input value against its closest tie.
+        String[] tieRelativePositions = {
+            "below", "exact", "above",
+            "below", "exact", "above",
+            "below", "exact", "above",
+            "below", "exact", "above"
+        };
+
+        // =============== Testing double (and thus float) value cases =========
+
+        System.out.println("\n===== testing 3 digits rounding position =====");
+        double[] values3FractDigits = {
+            // unimpacting values close to tie, with less than 3 input fract digits
+            1.115d, 1.125d, 1.135d,
+            // impacting close to tie values covering all 6 cases
+            0.3115d, 0.3125d, 0.3135d,
+            0.6865d, 0.6875d, 0.6885d,
+            // unimpacting values close to tie, with more than 3 input fract digits
+            1.46885d, 2.46875d, 1.46865d
+        };
+
+        String[] inputs3FractDigits = {
+            "1.115d", "1.125d", "1.135d",
+            "0.3115d", "0.3125d", "0.3135d",
+            "0.6865d", "0.6875d", "0.6885d",
+            "1.46885d", "2.46875d", "1.46865d"
+        };
+
+        String[][] expected3FractDigits = {
+            {"1.115", "1.125", "1.135",
+             "0.311", "0.312", "0.314",
+             "0.686", "0.687", "0.689",
+             "1.469", "2.469", "1.469"
+            },
+            {"1.115", "1.125", "1.135",
+             "0.311", "0.312", "0.314",
+             "0.686", "0.688", "0.689",
+             "1.469", "2.469", "1.469"
+            },
+            {"1.115", "1.125", "1.135",
+             "0.311", "0.313", "0.314",
+             "0.686", "0.688", "0.689",
+             "1.469", "2.469", "1.469"
+            },
+        };
+
+
+        for (int r = 0; r < roundingModes.length; r++) {
+            NumberFormat dfDefault = NumberFormat.getInstance(Locale.US);
+            RoundingMode rmode = roundingModes[r];
+            dfDefault.setRoundingMode(rmode);
+            System.out.println("\n----- Now checking " + rmode +
+                               " rounding mode -----");
+
+            for (int i = 0; i < values3FractDigits.length; i++) {
+                double d = values3FractDigits[i];
+                String tiePosition = tieRelativePositions[i];
+                String input = inputs3FractDigits[i];
+                String expected = expected3FractDigits[r][i];
+
+                formatOutputTestDouble(dfDefault, d, tiePosition, input, expected);
+            }
+        }
+
+        System.out.println("\n===== testing 5 digits rounding position =====");
+        double[] values5FractDigits = {
+            // unimpacting values close to tie, with less than 5 input fract digits
+            1.3135d, 1.3125d, 1.3115d,
+            // impacting values close to tie, covering all 6 cases
+            1.328115d, 1.328125d, 1.328135d,
+            1.796865d, 1.796875d, 1.796885d,
+            // unimpacting values close to tie, with more than 5 input fract digits
+            1.3281149999999d, 1.75390625d, 1.7968750000001d
+        };
+
+        String[] inputs5FractDigits = {
+            "1.3135d", "1.3125d", "1.3115d",
+            "1.328115d", "1.328125d", "1.328135d",
+            "1.796865d", "1.796875d", "1.796885d",
+            "1.3281149999999d", "1.75390625d", "1.7968750000001d"
+        };
+
+        String[][] expected5FractDigits = {
+            {"1.3135", "1.3125", "1.3115",
+             "1.32811", "1.32812", "1.32814",
+             "1.79686", "1.79687", "1.79689",
+             "1.32811", "1.75391", "1.79688"
+            },
+            {"1.3135", "1.3125", "1.3115",
+             "1.32811", "1.32812", "1.32814",
+             "1.79686", "1.79688", "1.79689",
+             "1.32811", "1.75391", "1.79688"
+            },
+            {"1.3135", "1.3125", "1.3115",
+             "1.32811", "1.32813", "1.32814",
+             "1.79686", "1.79688", "1.79689",
+             "1.32811", "1.75391", "1.79688"
+            }
+        };
+
+
+        for (int r = 0; r < roundingModes.length; r++) {
+            DecimalFormat df5 = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+            RoundingMode rmode = roundingModes[r];
+            df5.setRoundingMode(rmode);
+            System.out.println("\n----- Now checking " + rmode +
+                               " rounding mode -----");
+            df5.applyPattern("#,###.#####");
+
+            for (int i = 0; i < values5FractDigits.length; i++) {
+                double d = values5FractDigits[i];
+                String tiePosition = tieRelativePositions[i];
+                String input = inputs5FractDigits[i];
+                String expected = expected5FractDigits[r][i];
+
+                formatOutputTestDouble(df5, d, tiePosition, input, expected);
+            }
+        }
+
+        // ==================== Testing long value cases ====================
+
+        System.out.println("\n===== testing long values =====");
+        long l = 123456789012345L;
+        DecimalFormat dfLong = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+        String tiePosition = "exact";
+        String input = "123456789012345L";
+        String expected = "123,456,789,012,345";
+        String result = dfLong.format(l);
+        formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+        dfLong.applyPattern("0.###E0");
+        expected = "1.235E14";
+        formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+        l = 123450000000000L;
+        input = "123450000000000L";
+        expected = "1.234E14";
+        formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+        l = 987750000000000L;
+        input = "987750000000000L";
+        expected = "9.878E14";
+        formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+        dfLong.applyPattern("#,###.0E0");
+        l = 987755000000000L;
+        input = "987755000000000L";
+        expected = "987.76E12";
+
+        formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+
+        // ================= Testing BigInteger value cases =================
+
+        System.out.println("\n===== testing BigInteger values =====");
+        String stringValue = "12345678901234567890123456789012345";
+        BigInteger bi = new BigInteger(stringValue);
+        DecimalFormat dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+        tiePosition = "exact";
+        input = stringValue;
+        expected = "12,345,678,901,234,567,890,123,456,789,012,345";
+        formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+        dfBig.applyPattern("0.###E0");
+        expected = "1.235E34";
+        formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+        stringValue = "12345000000000000000000000000000000";
+        input = stringValue;
+        bi = new BigInteger(stringValue);
+        expected = "1.234E34";
+        formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+        stringValue = "12345000000000000000000000000000001";
+        input = stringValue;
+        bi = new BigInteger(stringValue);
+        expected = "1.235E34";
+        formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+        stringValue = "98755000000000000000000000000000000";
+        input = stringValue;
+        bi = new BigInteger(stringValue);
+        expected = "9.876E34";
+        formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+        dfLong.applyPattern("#,###.0E0");
+        stringValue = "98775500000000000000000000000000000";
+        input = stringValue;
+        expected = "987.76E34";
+
+        // =============== Testing BigDecimal value cases ================
+
+        System.out.println("\n===== testing BigDecimal values =====");
+        dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+
+        stringValue = "0.68850000000000000088817841970012523233890533447265625";
+        BigDecimal bd = new BigDecimal(stringValue);
+        tiePosition = "exact";
+        input = stringValue;
+        expected = "0.689";
+        formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
+
+        stringValue = "0.31149999999999999911182158029987476766109466552734375";
+        bd = new BigDecimal(stringValue);
+        dfBig.applyPattern("#,##0.####");
+        tiePosition = "exact";
+        input = stringValue;
+        expected = "0.3115";
+        formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
+
+        // ==================== Printing results and exiting ===================
+
+        System.out.println();
+        System.out.println("==> " + testCounter + " tests passed successfully");
+        System.out.println("==> " + errorCounter + " tests failed");
+
+        System.out.println();
+        if (allPassed) {
+            System.out.println(
+                "Success in formating all the values with the given parameters");
+        } else {
+            String s = "Test failed with " + errorCounter + " formating error(s).";
+            System.out.println(s);
+            throw new RuntimeException(s);
+        }
+    }
+}