将浮点数限制在两位小数。

2348

12
嗯...你是在尝试表示货币吗?如果是的话,你不应该使用浮点数表示美元。你可以使用浮点数表示便士,或者你正在尝试建模的最小通用货币单位,但最佳实践是使用十进制表示法,正如HUAGHAGUAH在他的答案中建议的那样。 - SingleNegationElimination
89
不要将货币表示为浮点数,而应该使用整数来表示分或美分数额。浮点数不够精确,而整数能够准确地表示货币数值。因此,整数是正确表示货币的方法。 - Davoud Taghawi-Nejad
5
基本上不需要(大多数情况下),用以分为单位的整数或者以便士为单位是很可靠的。这是代表货币的行业标准。如果你知道你在做什么,对浮点算术和Python的十进制类有充分的了解,可能会使用十进制表示法。但这取决于你的问题。你需要任意精度的小数吗?还是只需要两位数字?如果是两位数字:整数足矣。它会避免让你陷入麻烦。出处:我曾在银行软件咨询公司工作过。 - Davoud Taghawi-Nejad
35
我可能来得有点晚了,但我想问一下,Python的开发者已经解决了这个问题吗?因为当我执行round(13.949999999999999, 2)时,结果就是13.95。我已经在Python 2.7.6和3.4中尝试了一下,都可以工作。不确定2009年是否已经有Python 2.7版本。也许这只是Python 2.5的问题? - bad_keypoints
10
是的,Python 2.7.0+ 已经解决了舍入问题。更多信息请参见我的回答 - hynekcer
显示剩余6条评论
37个回答

10
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

结果:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'

我们能否返回 float 而不是 Decimal?像这样:def round_float(v, ndigits=2) -> float: d = Decimal(v); v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits)); return float(v_str) - alper
@alper,你可以返回任何你喜欢的内容。 - weaming

8
简单的解决方案在这里。
value = 5.34343
rounded_value = round(value, 2) # 5.34

2
这里有很多不必要的东西。8/3已经是float类型,所以float调用没有任何有用的作用。直接调用dunder方法有点奇怪-相反,只需调用委托给这些dunder方法的函数即可。因此,更好的拼写第一行的方法是简单地value = round(8/3, 2)。在那时,您实际上并没有添加任何其他答案中不存在的内容。 - Mark Dickinson
抱歉回答与问题无关。我以为那是正确的方法。此外,在问题部分,他提到round方法不起作用,所以我没有检查它。 - Praveen Kumar

8

可以像这样使用lambda函数:

arred = lambda x,n : x*(10**n)//1/(10**n)

这样你只需执行以下操作:
arred(3.141591657, 2)

并获取

3.14

"arred" 是什么意思?它是葡萄牙语单词吗? - Peter Mortensen
@PeterMortensen 只是一个函数的名称,它可以很容易地用 def 编写。在这里创建一个 lambda 只是为了炫耀,并没有特别的收益。 - Karl Knechtel
@PeterMortensen arred是“arredondamento”的缩写,意为葡萄牙语中的“rounding”。 - Pedro Chiiip
@Karl Knechtel 如果你使用“lambda”,你可以用更少的代码得到相同的结果。这就是为什么我更喜欢在可能的情况下使用它,而不是“def”。 - Gustavo Mirapalheta

8

这很简单,就像:

  1. use decimal module for fast correctly-rounded decimal floating point arithmetic:

     d = Decimal(10000000.0000009)
    

    to achieve rounding:

     d.quantize(Decimal('0.01'))
    

    will result with Decimal('10000000.00')

  2. make the above DRY:

    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))
    

    or

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
    

PS:对其他人的批评:格式不要圆整。

(注:此句话可能有歧义,如果需要更准确的翻译,请提供上下文。)

7
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54


7
在像Python和JavaScript这样的类型动态语言中修复浮点数问题时,我使用以下技巧。
# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

您也可以按以下方式使用Decimal:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')

1
getcontext().prec = 6 只在函数范围内有效还是全局都有效? - Julio Marins
1
上下文是算术操作的环境。它们控制精度,设置舍入规则,确定哪些信号被视为异常,并限制指数的范围。每个线程都有自己的当前上下文。@JulioMarins - Siamand

6

使用 format 函数是一个简单的解决方案。

float(format(num, '.2f'))

注意:我们将数字转换为浮点数,因为格式化方法返回的是字符串。


5
如果您希望处理货币,应使用Python的 decimal 模块。
from decimal import Decimal, ROUND_HALF_UP

# 'amount' can be integer, string, tuple, float, or another Decimal object
def to_money(amount) -> Decimal:
    money = Decimal(amount).quantize(Decimal('.00'), rounding=ROUND_HALF_UP)
    return money

我尝试在 DataFrame 的一列中使用这个,但是收到了如下消息: TypeError: 不支持从 Series 转换为 Decimal。 - Steve Maguire

4
lambda x, n:int(x*10^n + 0.5)/10^n

在许多语言中,这种方法已经为我工作了很多年。


似乎两个 '*' 连在一起会消失。 - Ray Tayek

3
为了将数字四舍五入到指定的精度,最好采用以下方法,可以适用于任何分辨率(如保留两位小数的0.01或其他步长):
>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0

在我的Python 3.4.3和Numpy 1.9.1上无法运行?
import numpy as np res = 0.01 value = 0.184 np.round(value/res) * res 0.17999999999999999
- szeitlin
1
寻找文档时,我发现问题出在numpy.round的精度上。因此,在与分辨率相乘之前需要将其定义为整数。我已经更新了代码。谢谢! - iblasi
唯一需要做的是将np.round的numpy.float64结果转换为float,或者简单地使用round(value, 2)。在13.949999999999999(=1395/100)和3.950000000000001(=1395*.01)之间不存在有效的IEEE 754数字。你为什么认为你的方法是最好的?原始值13.949999999999999289(= value = round(value, 2))甚至比你的13.95000000000000178(由np.float96打印)更精确。现在还为numpy添加了更多信息,可以在我的答案中找到,你可能误操作给它点了踩。它最初并不是关于numpy的。 - hynekcer
@hynekcer 我不认为我的答案是最好的。只是想添加一个将浮点数限制为n位小数但最接近定义分辨率的示例。我按照你说的检查了一下,发现在@szeitlin的示例中,可以使用float而不是int。感谢您的额外评论。(抱歉,我没有给你投反对票) - iblasi
添加完全新的数字处理依赖项(pandas)是“最佳方式”吗? - Hejazzman

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