在python中将浮点数转换为整数的最安全方法?
Posted
技术标签:
【中文标题】在python中将浮点数转换为整数的最安全方法?【英文标题】:Safest way to convert float to integer in python? 【发布时间】:2011-03-24 04:37:28 【问题描述】: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仍然返回float,所以这个问题是有效的。
标题可以改进为“在python中四舍五入并将浮点数转换为整数的最安全方法?”
【参考方案1】:
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:int
和 floor
当然会为负数返回不同的值。【参考方案2】:
所有可以用浮点数表示的整数都有一个精确的表示。所以你可以安全地在结果上使用int
。仅当您尝试使用不是 2 的幂的分母来表示有理数时,才会出现不精确的表示。
这个工作一点都不简单!如果所讨论的数字的大小足够小,则 int∘floor = ⌊⋅⌋ 是 IEEE 浮点表示的一个属性,但 int(floor(2.3)) 可能为 1 时可能会有不同的表示。
引用Wikipedia,
任何绝对值小于等于2的整数24都可以用单精度格式精确表示,任何绝对值小于等于2的整数53 sup> 可以用双精度格式精确表示。
【讨论】:
+1 表示更深入。你也可以简单解释一下原因:en.wikipedia.org/wiki/Floating_point:D 在 Python 2 中,“int”与 C 中的“int”相同。在 Python 3 中,“int,***.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【参考方案3】:你可以使用round函数。如果你不使用第二个参数(有效数字的#),那么我认为你会得到你想要的行为。
空闲输出。
>>> 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。
确实,round
和 floor
在 Python 3.x 中都返回整数。所以我想这个问题涉及 Python 2.x。
也许int(round(2.65))
?
为什么round(6.5)
给出6?在所有其他情况下,当小数点后立即有 5(或大于 9)时,这似乎有点像 ceil()
浮点数。为什么这在这种情况下不起作用?或任何其他数字以六结尾并且小数点后有一个 5 的情况......【参考方案4】:
使用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
舍入,在这种情况下即向上。相比之下,原始问题使用math.floor
,它总是向下取整:math.floor(-2.3)
给出-3.0
。
这不是问题。 OP 只想要math.floor
的结果中的一个整数,这个答案显示了如何将浮点数转换为整数。从math.floor
获取浮点数并将其通过int
管道,问题已解决:int(math.floor(2.3))
你读过这个问题吗?他知道 int() 函数,但询问您是否会在使用 1.9999 而不是 2.0 时遇到问题。你的答案根本不是一个答案,你错过了整点......【参考方案5】:
这很有效!如果所讨论的数字的大小足够小,则 int∘floor = ⌊⋅⌋ 是 IEEE 浮点表示的一个属性,但 int(floor(2.3)) 可能为 1 时可能会有不同的表示。
这篇文章解释了为什么它在这个范围内工作。
在双精度中,您可以毫无问题地表示 32 位整数。 不可能有任何舍入问题。更准确地说,双精度可以表示 253 和 -2 之间的所有整数53.
简短说明:一个 double 最多可以存储 53 个二进制数字。当您需要更多时,数字会在右侧用零填充。
因此 53 是可以存储的最大数字而无需填充。自然,所有需要较少位数的(整数)数字都可以准确存储。
向111(省略)111(53 个一)加一得到 100...000,(53 个零)。我们知道,我们可以存储 53 位数字,这使得最右边的零填充。
这就是 253 的来源。
更多细节:我们需要考虑 IEEE-754 浮点的工作原理。
1 bit 11 / 8 52 / 23 # bits double/single precision
[ sign | exponent | mantissa ]
然后按如下方式计算数量(不包括此处不相关的特殊情况):
-1符号 × 1.mantissa ×2指数 - 偏差
其中 bias = 2exponent - 1 - 1,即双精度/单精度分别为 1023 和 127。
知道乘以 2X 只是将所有位 X 位向左移动,很容易看出任何整数必须具有所有尾数中从小数点右边到零的位。
除零以外的任何整数都具有以下二进制形式:
1x...x 其中 x-es 表示 MSB 右侧的位(最高有效位)。
因为我们排除了零,所以总是有一个 MSB 为一,这就是它不被存储的原因。为了存储整数,我们必须把它变成上述形式:-1sign × 1.mantissa ×2exponent - bias。 p>
这与将位移动到小数点后的含义相同,直到 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
表示)设置为一,但这是不可能的。
【讨论】:
【参考方案6】:结合前面的两个结果,我们有:
int(round(some_float))
这可以相当可靠地将浮点数转换为整数。
【讨论】:
如果你尝试舍入一个很长的浮点数会发生什么?这至少会引发异常吗? @Agostino “非常长的浮动”是什么意思? @kralyk 我的意思是float
代表的数字大于普通int
可以容纳的数字。在 Python 2 中,是否存在只能使用 long
(舍入后)表示的 float
值?
@kralyk 你的意思是,在一轮之后?那么,将它们强制转换为 int 会引发异常,还是截断它们?
@Agostino 不,int()
函数根据需要生成int
或long
...【参考方案7】:
另一个使用变量将实数/浮点数转换为整数的代码示例。 “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))
【讨论】:
【参考方案8】:如果需要将字符串float转成int,可以使用这个方法。
示例:'38.0'
到 38
为了将其转换为 int,您可以将其转换为 float,然后再转换为 int。这也适用于浮点字符串或整数字符串。
>>> int(float('38.0'))
38
>>> int(float('38'))
38
注意:这将去除小数点后的所有数字。
>>> int(float('38.2'))
38
【讨论】:
【参考方案9】:由于您要求“最安全”的方式,我将提供除最佳答案之外的另一个答案。
确保不丢失任何精度的一种简单方法是检查转换后的值是否相等。
if int(some_value) == some_value:
some_value = int(some_value)
例如,如果浮点数为 1.0,则 1.0 等于 1。因此将执行到 int 的转换。如果浮点数为 1.1,则 int(1.1) 等于 1,并且 1.1 != 1。因此该值将保持为浮点数,并且不会丢失任何精度。
【讨论】:
以上是关于在python中将浮点数转换为整数的最安全方法?的主要内容,如果未能解决你的问题,请参考以下文章