将有理数四舍五入到最接近的整数,向上取整

Rounding a rational number to the nearest integer, with half-up

给定一个有理数,我需要得到最接近的整数,精确的一半四舍五入 up(即,朝向正无穷大)。结果 必须精确 ,这排除了 floatDecimal,两者的精度都有限。

以下代码在所有情况下都能完美运行除了负数

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))

例如,它成功于:

但是在

上失败了

我知道将 DecimalROUND_HALF_UPdecimal.getcontext().prec=99999 一起使用可能会造成混乱,但我想尽可能避免这种丑陋的 hack。如何做到这一点 没有任何舍入 -- 完全整合?

roundhalfup中,将int(...)替换为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))

这是一个使用 round 的解决方案。 尽管 Fraction.__round__ 执行的是“四舍五入”而不是“四舍五入”,但它更花哨一点:

from fractions import Fraction

def round_half_up(x: Fraction):
    if x.denominator == 2:
        if x.numerator % 2:
            return round(x + Fraction(1/2))
    else:
        return round(x)

X = [(5, 3), (4, 3), (1, 1), (2, 3), (1, 2), (1, 3), (0, 1), (-1, 3), (-1, 2),
     (-2, 3), (-3, 3), (-4, 3), (-5, 3),
     (3, 2)]

for x in X:
    f = Fraction(*x)
    print(f"{x}\t-> {round_half_up(f)}")

输出:

(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
(-2, 3) -> -1
(-3, 3) -> -1
(-4, 3) -> -1
(-5, 3) -> -2
(3, 2)  -> 2