Search code examples
javaroundingrounding-error

Java Rounding to 15 decimal place


I have the below codes round the forward rate to 15 decimal place. When _ForwardRate is 13,555.0, the result return is wrong.

public double round(double Number, int Decimal_Place) {     
    if (Number==0) return 0;
    double _plug = 0.000001;
    if (Number < 0) {
        _plug = -0.000001;
    }
    //Sometime a number is rounded down to 2.22499999999 by java. 
    //Actual precision is 2.245.  Without this plug, a 2 dp rounding result
    //in 2.22 when it should be 2.23
    double _newNumber = Number;
    if (Decimal_Place==2) {
        _newNumber = _newNumber+_plug;      
    }

    double _number_abs = Math.abs(_newNumber);  
    double _factor = Math.pow(10, Decimal_Place);
    double _rd = Math.round(_number_abs * _factor);
    double _r = _rd/_factor;
    if (Number <= 0)
        _r = _r * -1;

    return _r;
}

Double _ForwardRate = getForward_rate();
BigDecimal _fwdrate_bd = BigDecimal.valueOf(_ForwardRate.doubleValue());
_ForwardRate = round(new Double(_fwdrate_bd.doubleValue()), 15);

Current result

9,223.372036854777

Expected result

13,555.000000000000000

Solution

  • Your problem is that Math.round(double a) returns long, and you're overflowing.

    One easy way to do this, is to use BigDecimal:

    public static double round(double number, int decimalPlaces) {
        return BigDecimal.valueOf(number)
                         .setScale(decimalPlaces, RoundingMode.HALF_UP)
                         .doubleValue();
    }
    

    This allows you to control the rounding mode. Note that the rounding done by Math.round() is a HALF_CEILING which isn't supported by setScale().

    You might want to consider doing all you math using BigDecimal, if you need that level of precision.