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