简体   繁体   中英

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

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

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

The value of the double 21.255 is not exactly 21.255, it is actually closer to 21.25499999... , which means even with rounding mode HALF_EVEN , it will round down to 21.25 . Similarly the double 21.265 is actually closer to 21.26500000000000056... which means it will round up.

You can get the exact same behavior as DecimalFormat by using new BigDecimal(double) instead of new BigDecimal(String)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM