Reputation: 1036
I'm using the DecimalFormat with HALF_UP rounding mode and I have an escenery where is not working correctly and I don't know why.
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.HALF_UP);
float tmp = (float) (0.5 * 1.05);
df.format(tmp);
float mul = Float.parseFloat(df.format(tmp));
The mul
variable value I hope have 0.53 value and I received 0.52 value.
I'm using the Java 1.8.0_131.
SOLVED FINAL CODE
BigDecimal mul = new BigDecimal(0.5).multiply(new igDecimal(1.05));
mul = mul.setScale(2, RoundingMode.HALF_UP);
System.out.println(mul);
Upvotes: 1
Views: 1417
Reputation: 20608
You are using the float
datatype.
This datatype is not able to precisely hold the value 0.525
. See this code for making it clear:
float value = (float) (0.5 * 1.05);
DecimalFormat df = new DecimalFormat("#.########################");
System.out.println(df.format(value));
This prints out:
0.5249999761581421
Rounding such a value with the mode RoundingMode.HALF_UP
will correctly yield 0.52
.
The double
value seems to be able to precisely store the value 0.525
:
double value = 0.5 * 1.05;
DecimalFormat df = new DecimalFormat("#.########################");
System.out.println(df.format(value));
This will print the expected value:
0.525
Rounding that value with the mode RoundingMode.HALF_UP
will now yield 0.53
!
Caution: Even the double
datatype does not store the value precisely!
Look at @MarkDickinson's comment. The stored value is 0.52500000000000002220446049250313080847263336181640625
which happens to be larger than 0.525
and only rounds by accident to the expected value.
So what to do?
The data types float
and double
are binary-based, whereas we humans tend to think decimal-based when dealing with numbers. Read the article "What Every Computer Scientist Should Know About Floating-Point Arithmetic" for much more information.
The solution is to use a decimal-based data type, which exists in BigDecimal
.
Upvotes: 9