将有理数四舍五入为最接近的整数,并使用上半部分

2024-10-03 11:12:25 发布

您现在位置:Python中文网/ 问答频道 /正文

给定一个有理数,我需要得到最接近的整数,精确的一半向上取整(即,向正无穷大方向)。结果必须精确,这排除了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))

例如,它在以下方面成功:

  • (5,3)→ 二,
  • (4,3)→ 一,
  • (1,1)→ 一,
  • (2,3)→ 一,
  • (1,2)→ 一,
  • (1,3)→ 0
  • (0,1)→ 0
  • (-1,3)→ 0
  • (-1,2)→ 0

但它失败了

  • (-2,3)→ 0[应为-0.6̅→ -1]
  • (-3,3)→ 0[应为-1]→ -1]
  • (-4,3)→ 0[应为-1.3̅→ -1]
  • (-5,3)→ -1[应为-1.6̅→ -2]

我知道用Decimal^{}decimal.getcontext().prec=99999一起使用Decimal可能会使这个问题变得很棘手,但是如果可能的话,我想避免这种丑陋的黑客攻击。如何在没有任何舍入的情况下做到这一点?完全是整体的


Tags: 代码returndefnot情况精度整数float
2条回答

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的解决方案。 虽然由于^{}执行的是“向偶数取整”而不是“向上取整”,但它有点花哨:

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

相关问题 更多 >