Search code examples
javacurrencyrounding

How to customize rounding mode in Java?


I am trying to make some rounding for money in Java. I send it to Fiscal printer which has defined some rounding parameters.

There is one number which defines number of decimals ... for example x = 0.0100; Second number is some coefficient for rounding. For example y = 0.0050; All greater than 0.0050 should be rounded to 0.01 and all less than 0.0050 should be rounded to 0.00. BigDecimal is not solution because of this number which defines rounding mode.

In documentation of printer I have some table with examples of rounding numbers...

  • x = 0.0100; y = 0.0001; 15.2241 = 15.23; 15.0009 = 15.01
  • x = 0.0100; y = 0.0010; 15.2241 = 15.23; 15.0009 = 15.00
  • x = 0.0100; y = 0.0100; 15.2241 = 15.23; 15.0009 = 15.00
  • x = 0.0100; y = 0.0040; 15.2241 = 15.23
  • x = 0.0100; y = 0.0041; 15.2241 = 15.23
  • x = 0.0100; y = 0.0042; 15.2241 = 15.22
  • x = 0.1000; y = 0.0100; 15.2241 = 15.30; 0.0010 = 0.00
  • x = 1.0000; y = 0.5000; 15.2241 = 15.00; 0.0010 = 0.00
  • x = 1.0000; y = 0.0010; 15.2241 = 16.00; 0.0010 = 1.00

I was trying to solve this for few hours and I can't find the solution. This is my current code... handling decimal points with number x.

Math.round(value / x) * x;

How should I add there number "y" ... I tried few solutions and I still get bad values for some combinations of variables.

I checked this also, but it didn't work fine ... How to customize the form of rounding


Solution

  • I made function like this ... values seems to be ok, but one is still wrong ... x = 0.0100; y = 0.0100; 15.0009 = 15.01 It should be 15.00

    Code that was created by @SeanVanGorder is not very good because if x = 0.0200 ... value is wrong. My function makes x = 0.0200; y = 0.0030; 15.2241 = 15.24 and it should be like this ... rounding to first 2.

    Return type is double, because I didn't manage to make good rounding depended to variable x with BigDecimal. I will use return value only for writing to printer, so there shouldn't be problem with floating points etc., but if someone knows solution, feel free to post it. It is probably the best solution I made, but it is still not 100% fine.

    UPDATE: I updated to code... now it is working fully with BigDecimal and it is probably best solution for this problem. I wrote an email to manufacturer of printer and I got some reply that was in a conflict with description in manual for programmers. So, this is not 100% fine solution and one value is still wrong value = 15.0009; x = 0.0100; y = 0.0100; should be 15.00 (manual), but manufacturer wrote 15.01 and my code returns 15.01.

    static BigDecimal roundVaros(BigDecimal value, BigDecimal x, BigDecimal y) {
        BigDecimal a = value.divide(x, RoundingMode.HALF_UP);
        BigDecimal b = y.divide(x, RoundingMode.HALF_UP);
    
        a = a.subtract(BigDecimal.valueOf(a.longValue()));
        b = b.subtract(BigDecimal.valueOf(b.longValue()));
    
        if (a.compareTo(b) >= 0) {
            return value.divide(x, RoundingMode.HALF_UP).setScale(0, RoundingMode.CEILING).multiply(x);
        } else {
            return value.divide(x, RoundingMode.HALF_UP).setScale(0, RoundingMode.FLOOR).multiply(x);
        }
    }
    

    Thanks to @SeanVanGoder (his code helped me also)