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:
def roundhalfup(x: Fraction) -> int: "Returns the closest integer to x, with exact ties rounded up" #assert not x < 0, ValueError("Negative numbers not implemented") return int(x + Fraction(1, 2)) def divroundhalfup(a: int | Fraction, b: int | Fraction) -> int: return roundhalfup(Fraction(a, b))
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(...)
:
from math import floor def roundhalfup(x: Fraction) -> int: """ Returns the closest integer to x, with exact ties rounded up. """ return floor(x + Fraction(1, 2))