在Python中将float转换为整数的最安全方法?


215

Python的math模块包含诸如floor&的便捷函数ceil。这些函数采用浮点数,并在其下或上返回最接近的整数。但是,这些函数将答案作为浮点数返回。例如:

import math
f=math.floor(2.3)

现在f返回:

2.0

从该浮点数中获取整数而不冒取舍入错误风险的最安全方法是什么(例如,如果浮点数等于1.99999),或者我应该完全使用另一个函数?


7
math.floor 在v2.6中返回浮点数,但在v3中返回整数。在这一点上(OP之后将近六年),这个问题可能很少出现。
sancho.s ReinstateMonicaCellio

但是numpy仍然返回float,因此该问题有效。
Vincenzooo

Answers:


178

可以用浮点数表示的所有整数均具有精确的表示形式。这样您就可以安全地使用int结果了。仅当您尝试使用非2的幂的分母来表示有理数时,才会出现不精确的表示。

这项工作一点都不小!IEEE浮点表示的一个属性是int∘floor=⌊⋅⌋,如果所讨论的数字的大小足够小,但是int(floor(2.3))可能为1的情况下,可能会有不同的表示形式。

要引用维基百科

绝对值小于或等于2 24的任何整数都可以用单精度格式准确表示,绝对值小于或等于2 53的任何整数都可以用双精度格式准确表示。


8
+1会更深一些。您还可以对原因进行简要说明:en.wikipedia.org/wiki/Floating_point:D
Gordon Gustafson,2010年

在Python 2中,“ int”与C“ int”相同。在Python 3,似乎是没有限制到一个的大小为“int,stackoverflow.com/questions/13795758/...。的含义为‘int’也取决于操作系统和底层硬件上。参见en.wikipedia。 org / wiki / 64-bit_computing#64-bit_data_models。如果您正在使用C-API,python 3进行编程,则在平台上long和size_t的定义上要非常小心。docs.python.org/3 /c-api/long.html
胡安

112

使用int(your non integer number)将打钉。

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"

4
这不适用于负数:floor向下int
取整

1
@jochen我int(-2.3)在Python发行版Canopy 2.7.6中进行了测试,并得到了-2预期的结果。整数可以为负,与正式的Math定义相同。
srodriguex 2014年

5
我同意,int(-2.3)-2像你说的,因为它舍入到0最多在这种情况下。相反,最初使用的问题math.floor总是四舍五入:math.floor(-2.3)-3.0
jochen 2014年

1
那不是真正的问题。OP只是希望从的结果中获取一个整数math.floor,并且此答案显示了如何将浮点数转换为整数。math.floorintint(math.floor(2.3))
取下

4
你甚至读过这个问题吗?他知道int()函数,但是询问您是否可能在1.9999而不是2.0上遇到麻烦。您的答案根本不是一个答案,您错过了整个重点……
Mayou36 '16

48

您可以使用舍入功能。如果您不使用第二个参数(有效数字位数),那么我认为您将获得想要的行为。

空闲输出。

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2

28
round至少在Python 2.6中也返回一个浮点数。
菲利普

8
在Python 3.1.2中,round返回一个int。
罗伯特

2
的确,roundfloor在Python 3.x的回报整数 所以我想这个问题与Python 2.x有关。
菲利普

4
也许int(round(2.65))吧?
teewuane 2015年

1
为什么round(6.5)给6?ceil()在所有其他情况下,小数点后立即有5个(或更大的则为9)时,似乎有点浮动。为什么在这种情况下不起作用?或任何其他情况,当数字以6结尾并且在小数点后有5时…
candh

43

结合之前的两个结果,我们得到:

int(round(some_float))

这可以相当可靠地将浮点数转换为整数。


如果您尝试舍入很长的浮点数会怎样?这至少会引发例外吗?
Agostino

@Agostino你是什么意思“很长的浮动”?
kralyk '16

@kralyk我的意思是float代表一个大于正常值的数字int。在Python 2中,是否存在float只能使用long(四舍五入后)表示的值?
阿戈斯蒂诺

@kralyk你的意思是,在回合之后?那么,将它们强制转换为int会引发异常,还是只是截断它们?
Agostino

@Agostino不,该int()函数根据需要生成一个int或一个long...
kralyk

18

这项工作一点都不小!IEEE浮点表示的一个属性是int∘floor=⌊⋅⌋,如果所讨论的数字的大小足够小,但是int(floor(2.3))可能为1的情况下,可能会有不同的表示形式。

这篇文章解释了为什么它可以在这个范围内工作

在double中,您可以毫无问题地表示32位整数。有不能是任何四舍五入问题。更精确地,双精度数可以表示2 53-2 53之间(包括2 53-2 53)的所有整数。

简短说明:一个double最多可以存储53个二进制数字。当您需要更多时,该数字将在右边填充零。

由此可见,53个数字是无需填充即可存储的最大数字。自然,所有需要较少数字的(整数)数字都可以准确存储。

111加1(省略)111(53个)将产生100 ... 000,(53个零)。众所周知,我们可以存储53位数字,即最右边的零填充。

这是2 53的来源。


详细信息:我们需要考虑IEEE-754浮点如何工作。

  1 bit    11 / 8     52 / 23      # bits double/single precision
[ sign |  exponent | mantissa ]

然后,该数字的计算方式如下(不包括此处无关的特殊情况):

-1 ×1.尾数×2 指数-偏差

其中偏压= 2 指数- 1 1 -分别,即,1023和127,用于双/单精度。

明知乘以2 X根本改变所有位X位的左侧,可以很容易地看到,任何整数必须具备的所有位尾数为此右上小数点零。

除零以外的任何整数都具有以下二进制形式:

1x ... x,其中x -es表示MSB右侧的位(最高有效位)。

因为我们排除了零,所以总会有一个MSB为1,这就是为什么不存储它的原因。要存储整数,我们必须将其转换为上述形式:-1 符号 ×1.尾数×2 指数偏差

就是说,将这些位移到小数点后直到只有MSB朝MSB的左侧移动。然后,小数点右边的所有位都存储在尾数中。

由此可见,除MSB外,我们最多可以存储52个二进制数字。

因此,显式存储所有位的最高编号为

111(omitted)111.   that's 53 ones (52 + implicit 1) in the case of doubles.

为此,我们需要设置指数,以使小数点后移52位。如果我们将指数增加一,我们将无法知道小数点后左边的数字。

111(omitted)111x.

按照惯例,它是0。将整个尾数设置为零,我们收到以下数字:

100(omitted)00x. = 100(omitted)000.

这是一个1,后跟53个零,已存储52个,并且由于指数而加了1。

它代表2 53,它标志着我们可以准确表示所有整数的边界(负向和正向)。如果要将1加到2 53,则必须将隐式零(由表示x)设置为1,但这是不可能的。


8

math.floor将始终返回整数,因此int(math.floor(some_float))永远不会引入舍入错误。

但是,舍入错误可能已经引入了math.floor(some_large_float),或者甚至当首先将大量存储在float中时也已引入。(存储在浮点数中的大数字可能会失去精度。)


7
来自:docs.python.org/2/library/math.html-math.floor(x)-以浮点数形式返回x的底数,即小于或等于x的最大整数值。
Bill Rosmus 2013年

当int已经做同样的事情时,为什么还要调用math.floor?
亚历克斯(Alex)

1
@Alex:intfloor负数回报,当然不同的值。

8

如果需要将字符串float转换为int,则可以使用此方法。

例如:'38.0'38

为了将其转换为int,可以将其转换为float,然后转换为int。这也适用于浮点字符串或整数字符串。

>>> int(float('38.0'))
38
>>> int(float('38'))
38

注意:这将删除小数点后的所有数字。

>>> int(float('38.2'))
38

1

另一个代码示例使用变量将实数/浮点数转换为整数。“ vel”是一个实数/浮点数,并转换为第二高的整数“ newvel”。

import arcpy.math, os, sys, arcpy.da
.
.
with arcpy.da.SearchCursor(densifybkp,[floseg,vel,Length]) as cursor:
 for row in cursor:
    curvel = float(row[1])
    newvel = int(math.ceil(curvel))

0

由于您要求的是“最安全”的方式,因此我将提供除最佳答案之外的另一个答案。

确保您不损失任何精度的一种简单方法是检查转换后的值是否相等。

if int(some_value) == some_value:
     some_value = int(some_value)

例如,如果float为1.0,则1.0等于1。因此将执行向int的转换。如果float为1.1,则int(1.1)等于1,并且1.1!=1。因此,该值将保持为float值,并且不会损失任何精度。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.