有没有办法将python浮点数舍入为x小数?例如:
>>> x = roundfloat(66.66666666666, 4)
66.6667
>>>x = roundfloat(1.29578293, 6)
1.295783
我已经找到了修剪/截断它们的方法(66.666666666-> 66.6666),但是不是圆形的(66.666666666-> 66.6667)。
Answers:
使用内置功能round()
:
In [23]: round(66.66666666666,4)
Out[23]: 66.6667
In [24]: round(1.29578293,6)
Out[24]: 1.295783
帮助round()
:
round(number [,ndigits])->浮点数
将数字四舍五入到给定的精度(以十进制数字表示)(默认为0位数)。这总是返回一个浮点数。精度可能为负。
我不得不对阿什维尼·乔杜里的回答提出反驳。尽管有外观,该round
函数的两个参数形式并不能将Python浮点数舍入到给定的小数位数,并且即使您认为确实不是,它也不是您想要的解决方案。让我解释...
经常需要将(Python)浮点数舍入到小数点后位数的能力,但实际上很少需要这种能力。令人惊讶的简单答案round(x, number_of_places)
令人讨厌:它看起来像您想要的,但由于Python浮点数以二进制形式存储在内部,因此它的功能相当巧妙。考虑以下示例:
>>> round(52.15, 1)
52.1
随着一个什么样的幼稚理解round
呢,这看起来错了:当然应该四舍五入达至52.2
,而不是下降到52.1
?要理解为什么不能依靠这种行为,您需要了解,尽管这看起来像是一个简单的十进制到十进制的操作,但它远非简单。
因此,这就是上面示例中的实际情况。(深吸一口气)我们显示小数最近的表示二进制浮点数到最近n
-digits-后的点十进制数的二进制写在数字文本的浮点近似小数。因此,为了从原始的数字文字到显示的输出,底层的机器已经在二进制和十进制格式之间进行了四个单独的转换,每个方向上两个。分解(以及关于假定IEEE 754 binary64格式,四舍五入的舍入和IEEE 754规则的通常免责声明):
首先,将数字文字52.15
解析并转换为Python浮点数。实际存储的数字是7339460017730355 * 2**-47
或52.14999999999999857891452847979962825775146484375
。
在内部,作为round
操作的第一步,Python计算出与所存储的数字最接近的1位点后十进制字符串。由于该存储的数字比原始值小52.15
,因此最终四舍五入并得到一个字符串52.1
。这解释了为什么我们得到的52.1
是最终输出而不是52.2
。
然后,在round
操作的第二步中,Python将该字符串转换为浮点数,并获取最接近的二进制浮点数到52.1
,即现在的7332423143312589 * 2**-47
或52.10000000000000142108547152020037174224853515625
。
最后,作为Python的read-eval-print循环(REPL)的一部分,显示浮点值(十进制)。这涉及将二进制值转换回十进制字符串,52.1
作为最终输出。
在Python 2.7和更高版本中,我们有一个令人愉快的情况,步骤3和4中的两次转换相互抵消。这是由于Python选择了repr
实现,该实现会产生最短的十进制值,保证可以正确舍入到实际的float。该选择的一个结果是,如果您以有效位数为15或更少的任何(不是太大,不是太小)十进制文字开始,那么将显示相应的浮点数,以显示完全相同的数字:
>>> x = 15.34509809234
>>> x
15.34509809234
不幸的是,这进一步增加了Python将值存储为十进制的错觉。但是,在Python 2.6中不是这样!这是在Python 2.6中执行的原始示例:
>>> round(52.15, 1)
52.200000000000003
我们不仅朝相反的方向取整,52.2
取而代之52.1
,而且显示的值甚至不会打印为52.2
!此行为已导致许多错误报告给Python bug跟踪器,如“回合破裂!”。但这并不是round
坏的,而是用户的期望。(好吧,好吧,round
是一点点在Python 2.6打破,因为它不使用正确的舍入位。)
短版:如果你使用两个参数的圆,而您希望从可预测的行为二进制近似一个十进制一轮的二进制近似一个小数中途的情况下,你是在自找麻烦。
这样的论点就足以证明“两轮辩论是不好的”。什么应该您是使用呢?有几种可能,具体取决于您要执行的操作。
如果出于显示目的四舍五入,则根本不需要浮点数;你想要一个字符串。在这种情况下,答案是使用字符串格式:
>>> format(66.66666666666, '.4f')
'66.6667'
>>> format(1.29578293, '.6f')
'1.295783'
即使这样,也必须意识到内部二进制表示形式,以免对明显的十进制中途情况的行为感到惊讶。
>>> format(52.15, '.1f')
'52.1'
如果您在需要将小数点中途取整的方向取整的环境中(例如,在某些财务环境中),则可能需要使用该Decimal
类型来表示数字。在Decimal
类型上进行十进制舍入比在二进制类型上有意义得多(同样,在二进制类型上舍入到固定数量的二进制位也很有意义)。此外,该decimal
模块使您可以更好地控制舍入模式。在Python 3中,round
直接执行工作。在Python 2中,您需要该quantize
方法。
>>> Decimal('66.66666666666').quantize(Decimal('1e-4'))
Decimal('66.6667')
>>> Decimal('1.29578293').quantize(Decimal('1e-6'))
Decimal('1.295783')
在极少数情况下,round
真正需要的是两个参数的版本:也许是将浮动对象合并为大小为bin的容器0.01
,并且您并不特别在意边界案例的处理方式。但是,这些情况很少见,round
仅凭这些情况很难证明内置参数的两个参数版本的合理性。
float
应完全等同于使用round
。格式化操作再次是从二进制浮点到十进制字符串的转换,并且使用的是完全相同的机制round
。(对于Python 2,这有所不同,因为中途行为有所不同。)
python和numpy中的默认舍入:
In: [round(i) for i in np.arange(10) + .5]
Out: [0, 2, 2, 4, 4, 6, 6, 8, 8, 10]
我用它来将整数舍入到熊猫系列:
import decimal
并使用此行将舍入设置为“减半”,也就是在学校教过的舍入:
decimal.getcontext().rounding = decimal.ROUND_HALF_UP
最后,我实现了将此功能应用于熊猫系列对象
def roundint(value):
return value.apply(lambda x: int(decimal.Decimal(x).to_integral_value()))
所以现在你可以做 roundint(df.columnname)
对于数字:
In: [int(decimal.Decimal(i).to_integral_value()) for i in np.arange(10) + .5]
Out: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
信用:空手道
马克·狄金森(Mark Dickinson)的答案虽然很完整,但不适用于float(52.15)的情况。经过一些测试,有我正在使用的解决方案:
import decimal
def value_to_decimal(value, decimal_places):
decimal.getcontext().rounding = decimal.ROUND_HALF_UP # define rounding method
return decimal.Decimal(str(float(value))).quantize(decimal.Decimal('1e-{}'.format(decimal_places)))
(将“ value”转换为float然后转换为字符串非常重要,这样,“ value”可以是float,decimal,integer或string类型!)
希望这对任何人都有帮助。