258

Python 的数学模块包含方便的函数,如floor& ceil。这些函数采用浮点数并返回其下方或上方最接近的整数。然而,这些函数将答案作为浮点数返回。例如:

import math
f=math.floor(2.3)

现在f返回:

2.0

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

4

9 回答 9

201

所有可以用浮点数表示的整数都有精确的表示。所以你可以安全地使用int结果。仅当您尝试使用不是 2 的幂的分母来表示有理数时,才会出现不精确的表示。

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

引用维基百科

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

于 2010-08-02T12:25:50.637 回答
139

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

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"
于 2013-01-26T11:16:54.067 回答
56

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

空闲输出。

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2
于 2010-08-02T12:31:09.457 回答
47

结合前面的两个结果,我们有:

int(round(some_float))

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

于 2014-06-21T15:06:18.773 回答
19

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

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

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

简短说明:双精度数最多可存储 53 个二进制数字。当您需要更多时,该数字会在右侧用零填充。

因此,53 个是可以在没有填充的情况下存储的最大数字。自然,所有需要较少位数的(整数)数字都可以准确存储。

将 1 加到111(省略)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.mantissa ×2指数 - 偏差

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

知道乘以2 X只是将X的所有位向左移动,很容易看出任何整数必须使尾数中的所有位都在小数点右侧结束为零。

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

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

因为我们排除了零,所以总会有一个 MSB 为 1——这就是它不被存储的原因。为了存储整数,我们必须把它变成前面提到的形式:-1 sign × 1.mantissa ×2 exponent - bias

这与将位移动到小数点上的含义相同,直到只有 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,它标志着我们可以准确地表示所有整数的边界(负数和正数)。如果我们想在2 53上加一,我们必须将隐含的零(用 表示x)设置为一,但这是不可能的。

于 2013-01-26T16:24:58.293 回答
12

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

示例:'38.0'38

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

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

注意:这将去除小数点后的任何数字。

>>> int(float('38.2'))
38
于 2018-03-06T15:35:30.757 回答
9

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

但是,舍入误差可能已经引入math.floor(some_large_float),甚至在首先将大量数字存储在浮点数中时。(存储在浮点数中时,大数字可能会丢失精度。)

于 2010-08-02T12:25:45.243 回答
2

另一个使用变量将实数/浮点数转换为整数的代码示例。“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))
于 2016-04-08T17:18:42.673 回答
2

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

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

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

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

于 2018-09-21T15:20:54.770 回答