Given a rational number, I need to get the nearest integer, with exact halves rounded up (that is, towards positive infinity). The results must be exact, which rules out float
and Decimal
, both of which have finite precision.
The following code works perfectly in all cases except for negative numbers:
JavaScript
x
8
1
def roundhalfup(x: Fraction) -> int:
2
"Returns the closest integer to x, with exact ties rounded up"
3
#assert not x < 0, ValueError("Negative numbers not implemented")
4
return int(x + Fraction(1, 2))
5
6
def divroundhalfup(a: int | Fraction, b: int | Fraction) -> int:
7
return roundhalfup(Fraction(a, b))
8
For instance, it succeeds on:
- (5, 3) → 2
- (4, 3) → 1
- (1, 1) → 1
- (2, 3) → 1
- (1, 2) → 1
- (1, 3) → 0
- (0, 1) → 0
- (-1, 3) → 0
- (-1, 2) → 0
But it fails on
- (-2, 3) → 0 [Should be -0.6̅ → -1]
- (-3, 3) → 0 [Should be -1 → -1]
- (-4, 3) → 0 [Should be -1.3̅ → -1]
- (-5, 3) → -1 [Should be -1.6̅ → -2]
I know this could be kludged by using Decimal
with ROUND_HALF_UP
and decimal.getcontext().prec=99999
, but I’d like to avoid such an ugly hack if possible. How can this be done without any rounding — purely integrally?
Advertisement
Answer
In roundhalfup
, replace int(...)
with math.floor(...)
:
JavaScript
1
9
1
from math import floor
2
3
4
def roundhalfup(x: Fraction) -> int:
5
"""
6
Returns the closest integer to x, with exact ties rounded up.
7
"""
8
return floor(x + Fraction(1, 2))
9