Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Math RoundingMode.HALF_EVEN different results

It appears that HALF_EVEN rounding mode works differently in Java DecimalFormat than BigDecimal. Is there any way to make the DecimalFormat be consistent?

// Using BigDecimal scale
System.out.println("Big decimal scale (HALF_EVEN) of 21.255 ==> " + new BigDecimal("21.255").setScale(2, RoundingMode.HALF_EVEN));
System.out.println("Big decimal scale (HALF_EVEN) of 21.265 ==> " + new BigDecimal("21.265").setScale(2, RoundingMode.HALF_EVEN));

// Using DecimalFormat
DecimalFormat cdf = new DecimalFormat("#,##0.00");
cdf.setRoundingMode(RoundingMode.HALF_EVEN); // default anyway
System.out.println("Decimal format (HALF_EVEN) of 21.255 ==> " + cdf.format(21.255));
System.out.println("Decimal format (HALF_EVEN) of 21.265 ==> " + cdf.format(21.265));

Output:
Big decimal scale (HALF_EVEN) of 21.255 ==> 21.26
Big decimal scale (HALF_EVEN) of 21.265 ==> 21.26
Decimal format (HALF_EVEN) of 21.255 ==> 21.25
Decimal format (HALF_EVEN) of 21.265 ==> 21.27
like image 600
Sumon Rahman Avatar asked Jan 29 '23 06:01

Sumon Rahman


2 Answers

I just ran some tests : using @Mark Rotteveel solution :

cdf.format(new BigDecimal(21.255))

Big decimal scale (HALF_EVEN) of 21.255 ==> 21.26
Big decimal scale (HALF_EVEN) of 21.265 ==> 21.26
Decimal format (HALF_EVEN) of 21.255 ==> 21,25
Decimal format (HALF_EVEN) of 21.265 ==> 21,27 

using the BigDecimal String constructor:

cdf.format(new BigDecimal("21.255"))

Big decimal scale (HALF_EVEN) of 21.255 ==> 21.26
Big decimal scale (HALF_EVEN) of 21.265 ==> 21.26
Decimal format (HALF_EVEN) of 21.255 ==> 21,26
Decimal format (HALF_EVEN) of 21.265 ==> 21,26

So clearly, you have to use the String constructor to get the right result

like image 33
HBo Avatar answered Jan 30 '23 21:01

HBo


As said in the comment, if you try:

Double double1 = new Double(21.255);
BigDecimal bigDecimal1 = new BigDecimal(double1);
System.out.println(bigDecimal1);  //21.254999999999999005240169935859739780426025390625

Double double2 = new Double(21.265);
BigDecimal bigDecimal2 = new BigDecimal(double2);
System.out.println(bigDecimal2); //21.2650000000000005684341886080801486968994140625

You will find that:

  • double 21.255 is a little less than 21.255
  • double 21.265 is a little greater than 21.265

You can initiate the input as BigDecimal when using DecimalFormat to avoid losing accuracy:

System.out.println("Decimal format (HALF_EVEN) of 21.255 ==> " + cdf.format(new BigDecimal("21.255")));
//21.26
System.out.println("Decimal format (HALF_EVEN) of 21.265 ==> " + cdf.format(new BigDecimal("21.265")));
//21.26
like image 52
xingbin Avatar answered Jan 30 '23 21:01

xingbin