Python中的四舍五入保留两位小数

37

我需要向下取整,保留两位小数。


尝试了以下方法:

a = 28.266
print round(a, 2)

28.27

但是期望值只有28.26。


1
你想要截断。看这里:https://dev59.com/4Woy5IYBdhLWcg3wYc4l - zinjaai
1
@zinjaai的观点是对的,如果你参考了顶部答案。但是请注意评论中的内容:'%.3f'%(1324343032.3243) 和 '%.3f'%(1324343032.3245) 显示了不同的结果。这是因为顶部答案实际上等同于四舍五入。我建议在此使用@Psidom的回答。 - Corey Levinson
9个回答

54

看起来您需要使用 floor 函数:

import math
math.floor(a * 100)/100.0

# 28.26

32

看起来你想要截断,而不是四舍五入。

一个简单的方法是将 floor division // 和 regular division / 结合使用:

>>> a = 28.266
>>> a // 0.01 / 100
28.26

cmc在评论中提到的,你也可以使用乘法而不是常规的除法:

>>> a // 0.01 * 0.01
28.26

同样,你可以创建一个函数来将浮点数向其他更少或更多的小数位数舍入。但是由于浮点数是不精确的数字,这可能会导致不准确性。

def round_down(value, decimals):
    factor = 1 / (10 ** decimals)
    return (value // factor) * factor

print(round_down(28.266, 2))
# 28.26

但正如所说,它并不完全准确:

for i in range(0, 8):
    print(i, round_down(12.33333, i))
0 12.0
1 12.3
2 12.33
3 12.333
4 12.333300000000001 # weird, but almost correct
5 12.33332           # wrong
6 12.33333
7 12.33333

然而,还有其他(更精确)的方法:

使用 fraction 模块的解决方案

fraction 可以比 float 更准确地表示小数。因此,可以采用 Psidom 提到的“先乘,再下取整,再除”的方法,但精度显著提高:

import fractions
import math

a = 28.266

def round_down(value, decimals):
    factor = 10 ** decimals
    f = fractions.Fraction(value)
    return fractions.Fraction(math.floor(f * factor),  factor)

print(round_down(28.266, 2))
# 1413/50  <- that's 28.26

根据我使用浮点数进行的测试:

for i in range(0, 8):
    print(i, round_down(12.33333, i))
0 12
1 123/10
2 1233/100
3 12333/1000
4 123333/10000
5 1233333/100000
6 1233333/100000
7 1233333/100000

然而,创建一个 Fraction 并不能自动修复一个不精确的 float,因此通常应该从字符串或“分子-分母对”而不是从浮点数创建 Fraction

使用 decimal 模块的解决方案

您也可以使用 decimal 模块,它提供了多种舍入模式,包括向下舍入。

为了演示,我正在使用上下文管理器避免全局更改小数舍入模式:

import decimal

def round_down(value, decimals):
    with decimal.localcontext() as ctx:
        d = decimal.Decimal(value)
        ctx.rounding = decimal.ROUND_DOWN
        return round(d, decimals)

print(round_down(28.266, 2))  # 28.26

哪种舍入方法会得出更合理的结果:

for i in range(0, 8):
    print(i, round_down(12.33333, i))
0 12
1 12.3
2 12.33
3 12.333
4 12.3333
5 12.33333
6 12.333330
7 12.3333300

Fraction 不同,应该从字符串创建 Decimal 以避免中间的不准确浮点数。但是,Decimal 有限的精度意味着对于具有许多有效数字的值,它也会变得不准确。

然而,“向下取整”只是可用选项之一。可用的舍入模式列表很多:

舍入模式

decimal.ROUND_CEILING 向正无穷方向舍入。

decimal.ROUND_DOWN 向零方向舍入。

decimal.ROUND_FLOOR 向负无穷方向舍入。

decimal.ROUND_HALF_DOWN 舍入到最近接的数字,如果距离两个数字相等则朝向零的方向舍入。

decimal.ROUND_HALF_EVEN 舍入到最近的数字,如果距离两个数字相等则朝向最接近的偶数舍入。

decimal.ROUND_HALF_UP 舍入到最近接的数字,如果距离两个数字相等则远离零的方向舍入。

decimal.ROUND_UP 远离零方向舍入。

decimal.ROUND_05UP 如果在朝向零的方向舍入后,最后一位数字为0或5,则远离零方向舍入;否则向零方向舍入。


1
@user2682863 我的示例中提到的一些解决方案受到浮点数不精确的影响。但我注意到除了最后两个带有分数和小数的解决方案之外,每种方法都受到影响。 - MSeifert

11

使用Python 3,您可以使用quantize()

from decimal import *    
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')

6
这是一个简单的函数,不受浮点精度误差影响。
def truncate_float(n, places):
    return int(n * (10 ** places)) / 10 ** places

测试:

>>> truncate_float(28.266, 3)
28.266
>>> truncate_float(28.266, 2)
28.26
>>> truncate_float(28.266, 1)
28.2

4

只需尝试这个:

import math
a = 28.266
print((math.floor(a * 100)) / 100.0)

输出:

28.26

0

有3个字符的选项,但区别只在于除以1000和100,没有数学计算。

n = float(input())
print(int(n * 1000) / 1000)

或者

n = float(input())
print(n * 1000 //1 /1000)

或者

a=input()
print(float(a[:5])) # if the number of characters is known

0

一个简单的函数,您可以在您的代码中使用。这个函数也适用于整数向下取整。

import math
def floorDecimal(number, decimal):
    return math.floor(number * pow(10, decimal))/pow(10, decimal)

使用示例:

number = 256.789
newNumber = floorDecimal(number, 2) # newNumber is 256.78
newNumber = floorDecimal(number, -2) # newNumber is 200

0

这是我用于浮点数f和小数位数d的函数

from math import floor

def floor_decimal(f, d):
    n = 10 ** d
    return floor(f * n) / n

0

有一种更简单的通用方法,即在四舍五入之前减去一个小量,如下所示:

a = 28.269
digits = 2
print(round(a - 0.5/10**digits, digits))

这是基于一种直觉,即将浮点数四舍五入为最接近的整数的一种方法是添加0.5,然后截断。上述解决方案通过减去所需精度允许的最小“刻度”的一半,然后进行四舍五入来实现相反的效果。


1
如果您使用 digits = 3,那么结果是 28.268 - 这是不正确的。 - MSeifert
你说得对,对于某些值来说它偶尔会出现错误。这是因为round()函数使用了银行家舍入法吗? - guacamole
1
我认为差异是由于浮点数不精确,对于digits=3a - 0.5/10**digits实际上是28.268499999999999516830939683132...。然而,28.269也不能完全表示为浮点数:28.268999999999998351540853036568...。这就是为什么我的答案还展示了如何使用FractionDecimal来四舍五入值,因为分数是“真正精确的”,而十进制数几乎总是“足够精确的”(至少如果输入是以字符串形式给出的(而不是作为浮点数)。 - MSeifert

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