您似乎想要截断,而不是四舍五入。
一种简单的方法是将楼层除法// 和常规除法/ 结合起来:
>>> a = 28.266
>>> a // 0.01 / 100
28.26
除了常规除法之外,您还可以乘法(如 cmets 中 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 以避免中间不精确的浮点数。但与Fraction 不同,Decimal 的精度有限,因此对于具有大量有效数字的值也会变得不精确。
但是,“四舍五入”只是可用选项之一。 available rounding modes 的列表很广泛:
舍入模式
decimal.ROUND_CEILING 向无穷大旋转。
decimal.ROUND_DOWN 向零舍入。
decimal.ROUND_FLOOR 向 -Infinity 舍入。
decimal.ROUND_HALF_DOWN四舍五入,平局趋近于零。
decimal.ROUND_HALF_EVEN 舍入到最接近的整数,平数接近最接近的偶数。
decimal.ROUND_HALF_UP 舍入到最近的平局,从零开始。
decimal.ROUND_UP 从零取整。
decimal.ROUND_05UP 如果舍入到零后的最后一位是 0 或 5,则从零舍入;否则向零舍入。