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 ...;
}
}
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)