Java Math RoundingMode.HALF_EVEN different results

It seems that rounding mode HALF_EVENworks differently in Java DecimalFormatthan BigDecimal. Is there a way to make the sequence DecimalFormatconsistent?

// 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
+4
source share
3 answers

As the comment says, 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 slightly less 21.255
  • double 21.265 A bit more 21.265

You can initiate input as BigDecimalin use DecimalFormatto avoid loss of 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
+6
source

I just ran a few tests: using @Mark Rotteveel's 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 BigDecimalString 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

, , String

+1

The double value is 21.255not quite equal to 21.255, it is actually closer to 21.25499999..., which means even with rounding HALF_EVEN, it is rounded to 21.25. Likewise, the double 21.265is actually closer to 21.26500000000000056..., which means that it will be rounded.

You can get the same behavior as DecimalFormatusing new BigDecimal(double)insteadnew BigDecimal(String)

+1
source

Source: https://habr.com/ru/post/1696277/


All Articles