如何将浮点数向上舍入到特定的小数位?

96

假设我有 8.8333333333333339,我想将它转换为 8.84。在Python中如何实现?

round(8.8333333333333339, 2) 得到的结果是 8.83 而不是 8.84。我是Python或编程的新手。

我不想将其打印成字符串,并且结果将被进一步使用。有关问题的更多信息,请查看 Tim Wilson 的 Python 编程技巧:贷款和付款计算器


4
round(8.8333333333333339, 2) 的结果是 8.83,而不是 8.84。 - VGE
45
为什么是8.84?在保留两位小数时,8.8333333... 应该四舍五入为8.83。 - Tim Pietzcker
Python中的round函数似乎无法正确四舍五入。 - mouad
1
如果您想打印该值,请使用格式,例如print "%.2f"%8.8333333333333339。这将以2位小数打印该值。 - VGE
我修改了标题,因为这个问题在搜索“python round float”时很早就出现了,而且它可能不是大多数人想要的。希望新标题能让事情更清楚明白。 - jpmc26
1
这个回答解决了你的问题吗?将浮点数限制为两位小数 - Irfan wani
12个回答

108

8.833333333339(或8.833333333333334,即106.00/12的结果)保留两位小数应该是8.83。从数学上讲,你需要的似乎是向上取整函数。Python的math模块中有一个名为ceil的函数:

import math

v = 8.8333333333333339
print(math.ceil(v*100)/100)  # -> 8.84

地板函数和天花板函数一般将实数映射为最大的前一个或最小的后一个整数,其小数点后有零位 - 因此要将它们用于2位小数,首先将数字乘以102(或100)以移动小数点,然后再进行相应的除法运算来补偿。

如果由于某些原因您不想使用math模块,则可以使用我刚刚编写的这个(最小化测试的)实现:

def ceiling(x):
    n = int(x)
    return n if n-1 < x <= n else n+1

这与链接的贷款和付款计算器问题有何关联:

screenshot of loan calculator output

从样本输出来看,他们似乎将每月付款向上舍入,这就是许多人所称的天花板函数效应。这意味着每个月支付的总金额略高于112。这使得最后一次付款比通常少一点,只剩下8.76的未付余额。
同样使用正常舍入产生每月支付8.83和略高的最终支付8.87也是有效的。然而,在现实世界中,人们通常不喜欢付款增加,因此每次付款都向上舍入是常见做法 - 这也可以更快地将钱还给贷方。

70

这是正常现象(与Python无关),因为8.83不能完全表示为二进制浮点数,就像1/3不能在十进制中完全表示一样(0.333333...无限循环)。

如果您想确保绝对精度,您需要使用decimal模块:

>>> import decimal
>>> a = decimal.Decimal("8.833333333339")
>>> print(round(a,2))
8.83

如果您使用print函数/语句(取决于您的Python版本),则不会出现此问题。 - Tim Pietzcker
>>> 106.00/12 => 8.833333333333334 - martineau

23

你想使用decimal模块,但是你还需要指定舍入方式。以下是一个例子:

>>> import decimal
>>> decimal.Decimal('8.333333').quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_UP)
Decimal('8.34')
>>> decimal.Decimal('8.333333').quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_DOWN)
Decimal('8.33')
>>> 

14

一种更简单的方法是直接使用round()函数。以下是一个例子。

total_price = float()
price_1 = 2.99
price_2 = 0.99
total_price = price_1 + price_2

如果您现在打印total_price,您将得到:

3.9800000000000004

但是如果您将其放在round()函数中,如下所示

print(round(total_price,2))

输出等于

3.98

round()函数通过接受两个参数来工作。第一个参数是您要舍入的数字,第二个参数是要舍入到的小数位数。


10
使用内置的以下函数是最简单的方法:
format()

例如:

format(1.242563,".2f")

输出结果将是:
1.24

同样地:
format(9.165654,".1f")

would give:

9.2

格式答案在2010年已经给出这里。你本可以更新那个答案。 - ZF007

7
如果你将8.8333333333339四舍五入到两位小数,正确的答案是8.83,而不是8.84。你得到8.83000000001的原因是8.83是一个不能在二进制中正确表示的数字,并且它会给你最接近的数字。如果你想要打印它而不带有所有的零,请按照VGE的指示操作:
print "%.2f" % 8.833333333339   #(Replace number with the variable?)

6

如果你想四舍五入,8.84不是正确答案。8.833333333333 四舍五入应该是 8.83 而不是 8.84。如果你想总是向上取整,可以使用 math.ceil。两者结合使用时,请使用字符串格式化,因为对浮点数进行四舍五入本身是没有意义的。

"%.2f" % (math.ceil(x * 100) / 100)

5

仅供参考。你可以这样做:

def roundno(no):
    return int(no//1 + ((no%1)/0.5)//1)

不需要包含/导入文件



2

decimal.getcontext().prec = 3 decimal.Decimal(106)/decimal.Decimal(12) Decimal('8.83') 这就是我得到的结果,而不是8.84。
- hsinxh

2

这是我针对四舍五入问题的解决方案

< .5  round down

> = .5  round up

import math

def _should_round_down(val: float):
    if val < 0:
        return ((val * -1) % 1) < 0.5
    return (val % 1) < 0.5

def _round(val: float, ndigits=0):
    if ndigits > 0:
        val *= 10 ** (ndigits - 1)
    is_positive = val > 0
    tmp_val = val
    if not is_positive:
        tmp_val *= -1
    rounded_value = math.floor(tmp_val) if _should_round_down(val) else math.ceil(tmp_val)
    if not is_positive:
        rounded_value *= -1
    if ndigits > 0:
        rounded_value /= 10 ** (ndigits - 1)
    return rounded_value

# test
# nr = 12.2548
# for digit in range(0, 4):
#     print("{} decimals : {} -> {}".format(digit, nr, _round(nr, digit)))

# output
# 0 decimals : 12.2548 -> 12
# 1 decimals : 12.2548 -> 12.0
# 2 decimals : 12.2548 -> 12.3
# 3 decimals : 12.2548 -> 12.25

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