使用Python将数字四舍五入到最近的0.05。

20

如何在Python中进行以下舍入:

四舍五入到最接近的0.05小数位

7.97 -> 7.95

6.72 -> 6.70

31.06 -> 31.05

36.04 -> 36.05

5.25 -> 5.25

希望这样清楚明白。


1
我很惊讶没有一个使用“20”这个神奇数字的答案解释为什么选择它。 - martineau
7
@martineau 在这里记录下来,以防有人无法理解。20 == 1 / 0.05 - Chris Morgan
9个回答

32
def round_to(n, precision):
    correction = 0.5 if n >= 0 else -0.5
    return int( n/precision+correction ) * precision

def round_to_05(n):
    return round_to(n, 0.05)

round_to_05(-1) 给出的结果是 -0.95,这似乎不是正确的结果。 - David Webb
1
没错,我一开始考虑的是自然数……我会修改的。 - fortran
如果我们用 round(n / precision) * precision 替换 int(),则不需要进行 correction。那么包装函数也不再需要,因为这只是一行简单的代码。但是它确实有一些缺陷,比如 round(0.275/.05)*.05 == 0.30000000000000004。为了避免这种情况,可以使用 len(str(.05).split('.')[-1]) 来获取小数位数,并再次使用 round()0.30000000000000004 更改为 0.30 - mo-han

24

1
“decimal” 是 Python 标准库中的一个模块名称,因此您可能会希望避免使用该名称。 - martineau
@martineau - 你说得对,而且这也是一个不好的名称,因为第二个参数不一定要是小数,你也可以使用该函数将其舍入到整数,例如 round_to_value(36.04,5) 得到的结果是 35.0 - David Webb
+1,因为这是目前提供了一般解决方案的唯一答案(不出所料,我认为一般来说这更好)。 - martineau
在编程中,当你用“decimal”时其实想表达的是“fraction”,这绝对不会有助于理解。 - John Machin

4

我们开始吧。

round(VALUE*2.0, 1) / 2.0

敬礼


1
如果要四舍五入到半个单位,您应该乘以20再除以20。 - fortran

3

使用 Lambda 函数:

>>> nearest_half = lambda x: round(x * 2) / 2
>>> nearest_half(5.2)
5.0
>>> nearest_half(5.25)
5.5
>>> nearest_half(5.26)
5.5
>>> nearest_half(5.5)
5.5
>>> nearest_half(5.75)
6.0

3

这是一个简短的语句

def roundto(number, multiple):
   return number+multiple/2 - ((number+multiple/2) % multiple)

2

要将其四舍五入到您想要的精度:

>>> def foo(x, base=0.05):
...     return round(base*round(x/base), 2)

>>> foo(5.75)
5.75
>>> foo(5.775)
5.8
>>> foo(5.77)
5.75
>>> foo(7.97)
7.95
>>> foo(6.72)
6.7
>>> foo(31.06)
31.05
>>> foo(36.04)
36.05
>>> foo(5.25)
5.25

0
import numpy as np

对于Roundup
df['a']=(df["a"]*2).apply(np.ceil)/2

对于Round函数
df['a']=(df["a"]*2).apply(np.floor)/2

这是使用numpy进行四舍五入0.5的列处理...


0

我也遇到过同样的问题,并且由于没有找到“终极”解决方案,所以我提供我的方法。

首先是主要部分(之前已经回答过了):

def round_to_precision(x, precision):
    # This correction required due to float errors and aims to avoid cases like:
    # 100.00501 / 0.00001 = 10000500.999999998
    # It has a downside as well - it may lead to vanishing the difference for case like
    # price = 100.5 - (correction - correction/10), precision = 1 => 101 not 100
    # 5 decimals below desired precision looks safe enough to ignore
    correction = 1e-5 if x > 0 else -1e-5
    result = round(x / precision + correction) * precision
    return round(result, find_first_meaningful_decimal(precision))

这里唯一有点棘手的地方是find_first_meaningful_decimal,我已经实现了以下代码:

def find_first_meaningful_decimal(x):
    candidate = 0
    MAX_DECIMAL = 10
    EPSILON = 1 / 10 ** MAX_DECIMAL
    while round(x, candidate) < EPSILON:
        candidate +=1
        if candidate > MAX_DECIMAL:
            raise Exception('Number is too small: {}'.format(x))
    if int(x * 10 ** (candidate + 1)) == 5:
        candidate += 1
    return candidate


print(round_to_precision(129.950002, 0.0005))
print(round_to_precision(-129.95005, 0.0001))

129.9505
-129.9501

-1

接受答案的扩展。

def round_to(n, precision):
    correction = precision if n >= 0 else -precision
    return round(int(n/precision+correction)*precision, len(str(precision).split('.')[1]))


test_cases = [101.001, 101.002, 101.003, 101.004, 101.005, 101.006, 101.007, 101.008, 101.009]
[round_to(-x, 0.003) for x in test_cases]
[-101.001, -101.001, -101.001, -101.004, -101.004, -101.004, -101.007, -101.007, -101.007]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接