1

We are replacing some sybase code to Java and having issue with Rounding BigDecimal to match what sybase returns

11.4443999999999999062083588796667754650115966796875 - Should return 11.44

and

35.9549999999999982946974341757595539093017578125 - should return 35.96

I have tried all different rounding options with scale set to 2, but none works for both. What is the best option?

phuclv
  • 37,963
  • 15
  • 156
  • 475
basu76
  • 441
  • 10
  • 19
  • 2
    This question was already answered here: [Rounding BigDecimal to *always* have two decimal places](https://stackoverflow.com/questions/15643280/rounding-bigdecimal-to-always-have-two-decimal-places). Just replace the **RoundingMode** from `RoundingMode.CEILING` to `RoundingMode.HALF_UP` – Victor Ortiz Jan 06 '19 at 07:53
  • As I mentioned I tried all options, and HALFUP works on the first one and returns the desired output of 11.44, while on the second one it returns 35.95, while the desired out is 35.96 – basu76 Jan 06 '19 at 13:05
  • 35.954999... would be 35.95 after rounding to 2 digits, not 35.95. If rounded to 3 digits it'd be 35.955. If you round the value to 35.955 then to 35.96 then it's a [double rounding error](https://en.wikipedia.org/wiki/Rounding#Double_rounding), https://www.exploringbinary.com/double-rounding-errors-in-floating-point-conversions/ – phuclv Jan 06 '19 at 15:20
  • 1
    The "desired" output may be 35.96, but it **should be** 35.95 alright. So ISTM that your expectations are wrong. 35.95499... is **below** the exact halfway value 35.955, so it is rounded down to 35.95. – Rudy Velthuis Jan 06 '19 at 20:15
  • 1
    Possible duplicate of [Rounding BigDecimal to \*always\* have two decimal places](https://stackoverflow.com/questions/15643280/rounding-bigdecimal-to-always-have-two-decimal-places) – Vishwa Ratna Jan 07 '19 at 08:16

2 Answers2

0

This solution is not efficient but it gets the job done.

Source code

import java.math.BigDecimal;

public class BigDecimalRound {
    public static void main(String[] args) {
        BigDecimal bd;
        float f;

        bd = new BigDecimal(11.4443999999999999062083588796667754650115966796875);
        f = roundBigDecimal(bd, 2);
        System.out.println("bd: " + bd + ", f: " + f);

        bd = new BigDecimal(35.9549999999999982946974341757595539093017578125);
        f = roundBigDecimal(bd, 2);
        System.out.println("bd: " + bd + ", f: " + f);
    }

    public static float roundBigDecimal(BigDecimal bd, int precision) {
        int i = (int) Math.pow(10, precision);
        return (float) Math.round(bd.floatValue() * i) / i;
    }
}

Output

bd: 11.4443999999999999062083588796667754650115966796875, f: 11.44
bd: 35.9549999999999982946974341757595539093017578125, f: 35.96
Victor Ortiz
  • 206
  • 1
  • 5
0

You'll have to take a two-step approach. First round to scale 3, then to scale 2, using RoundingMode.HALF_UP:

BigDecimal value1 = new BigDecimal("11.4443999999999999062083588796667754650115966796875");      
BigDecimal value2 = new BigDecimal("35.9549999999999982946974341757595539093017578125"); 

BigDecimal rounded1 = value1.setScale(3, RoundingMode.HALF_UP); // 11.444
rounded1 = rounded1.setScale(2, RoundingMode.HALF_UP);          // 11.44

BigDecimal rounded2 = value2.setScale(3, RoundingMode.HALF_UP); // 35.955
rounded2 = rounded2.setScale(2, RoundingMode.HALF_UP);          // 35.96
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • Ended up doing this way. Looking at the SQL code, they had a precision of 4 set on it first and then rounding it, that worked !! – basu76 Jan 08 '19 at 07:04