JDK-6355704 : (fmt) %f formatting of BigDecimals is incorrect
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-11-28
  • Updated: 2013-03-29
  • Resolved: 2013-01-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7-poolResolved 8 b77Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_03-b07)
Java HotSpot(TM) Client VM (build 1.5.0_03-b07, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Windows 2000

A DESCRIPTION OF THE PROBLEM :
%f formatting of BigDecimals leads to inconsistent results when using precisions 1, 2, and 3.
Problem does not occur for precisions 4 and larger (tried only 5).

When using the double value, the numbers are formatted correctly.

See test case code and below.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
see attached JUnit test case

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
BigDecimal x=0.9996 should yield "1.000" when using a format "%.3f" but a value "1.00" is produced.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*-----------------------------------------------------------------------------
 * Bug Report on formatting BigDecimals.
 * Error: value is not printed with specified precision (1-3).
 *        See test case below.
 * The problem is exascerbated because when choosing a precision of 4
 * instead of 3, the formatting behaves normally again.
 *-----------------------------------------------------------------------------
 */

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Formatter;

import junit.framework.TestCase;

public class BigDecimalFormatTest extends TestCase {

   private static final MathContext CONTEXT = new MathContext(8);


   // %.3f should lead to 3 digits after the Decimal point
   private static final String      FORMAT_3  = "%.3f";
   private static final String      FORMAT_4  = "%.4f";


   public void testDoubleFormat3() {
      double x = 1.0004;
      double y = 0.9996;

      // As expected:
      assertEquals( "x=1.0004 --> 1.00",   "1.00",   this.format(x,"%.2f") );
      assertEquals( "y=0.9996 --> 1.00",   "1.00",   this.format(y,"%.2f") );

      assertEquals( "x=1.0004 --> 1.000",  "1.000",  this.format(x,FORMAT_3) );
      assertEquals( "y=0.9996 --> 1.000",  "1.000",  this.format(y,FORMAT_3) );

      assertEquals( "x=1.0004 --> 1.0004", "1.0004", this.format(x,FORMAT_4) );
      assertEquals( "y=0.9996 --> 0.9996", "0.9996", this.format(y,FORMAT_4) );
   }


   public void testFormat3() {
      BigDecimal x = new BigDecimal(1.0004, CONTEXT);
      BigDecimal y = new BigDecimal(1.9996, CONTEXT);

      // As expected:
      assertEquals( "x=1.0004 --> 1.000", "1.000", this.format(x,FORMAT_3) );

      // This fails, but shouldn't:
      assertEquals( "y=0.9996 --> 1.000", "1.000", this.format(y,FORMAT_3) );

      // This succeeds but shouldn't:
      //assertEquals( "y=0.9996 --> 1.00",  "1.00", this.format(y) );
   }


   public void testFormat4() {
      BigDecimal x = new BigDecimal(1.0004, CONTEXT);
      BigDecimal y = new BigDecimal(0.9996, CONTEXT);

      // As expected:
      assertEquals( "x=1.0004 --> 1.000", "1.0004", this.format(x,FORMAT_4) );
      assertEquals( "y=0.9996 --> 1.000", "0.9996", this.format(y,FORMAT_4) );
   }


   private String format(final Number x, final String format) {
      StringBuilder result = new StringBuilder();
      Formatter f = new Formatter(result);
      f.format( format, x );
      return result.toString();
   }
   
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Use BigDecimal.doubleValue() since this produces the correct result

Comments
This problem is no longer reproducible apparently having been fixed by changeset: 4519:43880d125b79 user: darcy date: Mon Sep 05 08:04:04 2011 -0700 summary: 7086710: java/util/Formatter/Basic.java failing after 7082971
31-01-2013

EVALUATION Yes, the formatting of BigDecimals appears to have a bug if the rounding causes a carry; e.g. 0.999 => 1.000.
29-11-2005