Search code examples
javarounding

How to round a double to the closest odd integer in Java?


I want to round a double to the closest odd mathematical integer (long) in Java. Here is a test program:

public class RoundToOdd {

    public static void main(String[] args) {
        System.out.println(roundToOdd(2.1)); // expected: 3
        System.out.println(roundToOdd(4.9)); // expected: 5
        System.out.println(roundToOdd(3.7)); // expected: 3
        System.out.println(roundToOdd(1.1)); // expected: 1
        System.out.println(roundToOdd(7.0)); // expected: 7
        System.out.println(roundToOdd(2.0)); // expected: 1 or 3, depends on requirements
    }

    public static long roundToOdd(double d) {
        return ...;
    }
}

Solution

  • The following function solves all the test cases listed at the end of this post.

    public static long roundToOdd(double d) {
        if (d > Long.MAX_VALUE) {
            return Long.MAX_VALUE;
        } else if (d <= Long.MIN_VALUE) {
            return Long.MIN_VALUE + 1;
        }
    
        return Math.round((d + 1.0) / 2.0) * 2 - 1;
    }
    

    The most important part of this function is the formula Math.round((d + 1.0) / 2.0) * 2 - 1, which calculates the result for all finite numbers d with

    Long.MIN_VALUE < d <= Long.MAX_VALUE or d being NaN (not a number).

    Math.round((d + 1.0) / 2.0) * 2 - 1 first translates the number d to one higher (d + 1.0) and then rounds to an even number by doing the steps /2, rounding to integer, and *2 in this order. This result is too high by 1, because we added 1 before rounding, so in the end we have to do -1 to reach the correct odd number.
    If d is NaN, then the result is -1, because Math.round(Double.NaN) results in 0.

    The if's test for special cases, which are all values higher than Long.MAX_VALUE or lower than or equal to Long.MIN_VALUE (this includes +Infinity / -Infinity). These are special cases, because no matter how far d is below Long.MIN_VALUE, the closest odd long value to d then is Long.MIN_VALUE + 1, or respectively no matter how far d is above Long.MAX_VALUE, the closest odd long value then is Long.MAX_VALUE.

    Test cases:

    -Infinity -> -9223372036854775807 ✔️ (expected -9223372036854775807)
    -9223372036854775808.0 -> -9223372036854775807 ✔️ (expected -9223372036854775807)
    -1152921504606846976.0 -> -1152921504606846977 ✔️ (expected one of [-1152921504606846977, -1152921504606846975])
    -9007199254740994.0 -> -9007199254740993 ✔️ (expected one of [-9007199254740995, -9007199254740993])
    -9007199254740992.0 -> -9007199254740991 ✔️ (expected one of [-9007199254740993, -9007199254740991])
    -7.0 -> -7 ✔️ (expected -7)
    -4.9 -> -5 ✔️ (expected -5)
    -3.7 -> -3 ✔️ (expected -3)
    -2.1 -> -3 ✔️ (expected -3)
    -2.0 -> -1 ✔️ (expected one of [-1, -3])
    -1.1 -> -1 ✔️ (expected -1)
    -0.1 -> -1 ✔️ (expected -1)
    0.0 -> 1 ✔️ (expected one of [-1, 1])
    0.1 -> 1 ✔️ (expected 1)
    1.1 -> 1 ✔️ (expected 1)
    2.0 -> 3 ✔️ (expected one of [1, 3])
    2.1 -> 3 ✔️ (expected 3)
    3.7 -> 3 ✔️ (expected 3)
    4.9 -> 5 ✔️ (expected 5)
    7.0 -> 7 ✔️ (expected 7)
    9007199254740992.0 -> 9007199254740991 ✔️ (expected one of [9007199254740991, 9007199254740993])
    9007199254740994.0 -> 9007199254740995 ✔️ (expected one of [9007199254740993, 9007199254740995])
    1152921504606846976.0 -> 1152921504606846975 ✔️ (expected one of [1152921504606846975, 1152921504606846977])
    9223372036854775808.0 -> 9223372036854775807 ✔️ (expected 9223372036854775807)
    Infinity -> 9223372036854775807 ✔️ (expected 9223372036854775807)
    NaN -> -1 ✔️ (expected -1)