0

I realize that the real answer is "don't use floating point numbers, use BigDecimal" but that will be a longer-term change in a large codebase.

My problem is relatively simple - I have numbers (doubles), both positive and negative, that I want to round towards zero to the nearest whole number. However, in the case of floating point imprecision errors, I need them to be rounded to the "actual" number.

Examples:

  • 351.365 rounds to 351
  • 3.9991532 rounds to 3
  • 3.9999999999999996 rounds to 4
  • -4.5 rounds to -4
  • -123.9999999999993 rounds to -124

I guess for the purposes of this question, we can just ignore the fact that the rounding errors are caused by floating point imprecision, and rephrase the requirements as:

"Round towards zero to the nearest whole number, unless the value is less than 1e-6 away from a whole number N, in which case round to N."

My code is gross (particularly the "% 1" feels wrong, and I know that there could be a loss of precision casting double to int, but for simplicity just assume that the double values are all less than Integer.MAX_VALUE):

private int getRoundedValue(double d) {
    double fractionalPart = d % 1;
    if (Math.abs(fractionalPart) < 1e-6 || (1 - Math.abs(fractionalPart) < 1e-6)) {
        
        // here we are close enough to a whole number so just round to it (up or down)
        return (int) Math.round(d);
    }

    // otherwise just return the nearest whole number towards zero
    return (int) d;  
} 

How can I improve the above method?

3
  • 1
    Have you taken a look at BigDecimal and the methods it offers?
    – f1sh
    Commented Feb 2, 2022 at 19:18
  • 2
    Round towards zero to the nearest whole number, unless the value is less than 1e-6 away from a whole number N, in which case round to N So add 1e-6 to the absolute value of the number, round the result towards 0, and put the sign back on. Not sure that'll be any less 'gross' than what you already have. Commented Feb 2, 2022 at 19:23
  • @fish - Yes, I know that's the way to go, but see my first sentence.
    – Jer
    Commented Feb 2, 2022 at 19:24

1 Answer 1

1

Here's a simpler version:

private static int getRoundedValue(double d) {
    return Math.toIntExact((long)(Math.round(d * 1e6) / 1e6));
}

Math.toIntExact throws ArithmeticException on overflows.

1

Not the answer you're looking for? Browse other questions tagged or ask your own question.