ChatGPT解决这个技术问题 Extra ChatGPT

在python中将浮点数转换为整数的最安全方法?

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

import math
f=math.floor(2.3)

现在 f 返回:

2.0

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

math.floor returns a float in v2.6,但 it returns an integer in v3。在这一点上(在 OP 之后将近六年),这个问题可能很少出现。
但是 numpy 仍然返回浮点数,所以这个问题是有效的。
标题可以改进为“在 python 中四舍五入并将浮点数转换为整数的最安全方法?”

P
Philipp

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

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

引用 Wikipedia

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


+1 更深入一点。您还可以简要说明原因:en.wikipedia.org/wiki/Floating_point:D
在 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
J
Jens Erat

使用 int(your non integer number) 会搞定它。

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

这不适用于负数:floor 向下舍入,而 int 向 0 舍入。
@jochen 我在 Python 发行版 Canopy 2.7.6 中测试了 int(-2.3) 并按预期得到了 -2。整数可以是负数,与正式数学定义中的方式相同。
我同意,如您所说,int(-2.3) 给出 -2,因为它向 0 舍入,在这种情况下 ie 向上。相反,原始问题使用 math.floor,它总是向下取整:math.floor(-2.3) 给出 -3.0
这不是一个真正的问题。 OP 只想要 math.floor 的结果中的一个整数,这个答案显示了如何将浮点数转换为整数。从 math.floor 获取浮点数并将其通过 int 管道,问题已解决:int(math.floor(2.3))
你甚至读过这个问题吗?他知道 int() 函数,但询问您是否会在使用 1.9999 而不是 2.0 时遇到问题。你的答案根本不接近答案,你错过了整个重点......
Y
Yarin

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

空闲输出。

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

round 也返回一个浮点数,至少在 Python 2.6 中是这样。
在 Python 3.1.2 中,round 返回一个 int。
实际上,roundfloor 在 Python 3.x 中都返回整数。所以我认为这个问题与 Python 2.x 有关。
所以也许 int(round(2.65))
为什么 round(6.5) 给出 6?在所有其他情况下,当小数点后立即有 5(或大于 9)时,它似乎有点 ceil() 浮点数。为什么这在这种情况下不起作用?或者当数字以六结尾并且小数点后有一个 5 时的任何其他情况......
M
Matt

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

int(round(some_float))

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


如果您尝试舍入一个很长的浮点数会发生什么?这至少会引发异常吗?
@Agostino你是什么意思“很长的浮动”?
@kralyk 我的意思是一个 float 代表一个比正常 int 可以容纳的数字更大的数字。在 Python 2 中,是否存在只能使用 long 表示的 float 值(四舍五入后)?
@kralyk 你的意思是,在一轮之后?那么,将它们强制转换为 int 会引发异常,还是截断它们?
@Agostino 不,int() 函数根据需要生成 intlong ...
p
phant0m

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

这篇文章解释了为什么它在该范围内有效。

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

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

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

将 1 加到 111(省略)111(53 个一)得到 100...000,(53 个零)。正如我们所知,我们可以存储 53 个数字,这使得最右边的零填充。

这就是 253 的来源。

更多细节:我们需要考虑 IEEE-754 浮点是如何工作的。

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

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

-1sign × 1.mantissa ×2exponent - 偏差

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

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

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

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

因为我们排除了零,所以总会有一个 MSB 为 1——这就是它不被存储的原因。要存储整数,我们必须将其带入上述形式:-1sign × 1.mantissa ×2exponent - 偏差。

这与将位移动到小数点上的含义相同,直到只有 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 由于指数而添加。

它代表253,它标志着我们可以准确表示所有整数的边界(负数和正数)。如果我们想给 253 加一,我们必须将隐含的零(用 x 表示)设置为一,但这是不可能的。


b
brandonbanks

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

示例:'38.0'38

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

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

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

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

佚名

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

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


来自:docs.python.org/2/library/math.html - math.floor(x) - 将 x 的下限返回为浮点数,即小于或等于 x 的最大整数值。
当 int 已经做了同样的事情时,为什么还需要调用 math.floor ?
@Alex:当然,intfloor 返回不同的负数值。
m
mrichey56

另一个使用变量将实数/浮点数转换为整数的代码示例。 “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))

T
Troy H

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

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

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。因此该值将保持为浮点数,并且不会丢失任何精度。