为什么整数除法会产生浮点数而不是另一个整数?

275

考虑在Python 3中进行的这个除法:

>>> 2/2
1.0

这是有意的吗?我非常记得早期版本返回 int/int = int。我该怎么办?是否有一个新的除法运算符或者我必须总是转换类型?


在2.x版本中,行为确实被颠倒了;请参阅如何强制执行浮点数除法?除法始终向下舍入到0? 以获取相反的、特定于2.x的问题。


38
是的,在3.x版本中除法是这样工作的。 - hughdbrown
3
这是Python创建者的一篇文章,讨论了Python中的四舍五入规则。虽然这与你的问题无关,但我觉得很有趣:http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html - Aaron D
@hughdbrown 这意味着基本上适用于所有Python 3版本? - Charlie Parker
@hughdbrown:是的,PEP已经最终,这意味着它已被接受并实现。 - Jonas Byström
如果你正在进行除法以外的其他计算,那么将浮点数结果转换为整型是更好的方法。例如,计算480 // 640 * 320的结果为0。 - brianlmerritt
1
@brianlmerritt 取决于你在做什么以及为什么要这样做。使用整数算术更加直观,而精度问题通常可以通过确保乘法发生在除法之前来解决:480 * 320 // 640 得到预期的 240 - Karl Knechtel
4个回答

328

请参阅PEP-238:更改除法运算符

//运算符可用于请求取整除,以避免歧义。


12
除了为 Python 2.0 编写的所有代码外,我觉得应该颠倒 / 和 // 的角色以保持向后兼容性。此外,在几乎所有其他语言中,/ 保留类型。因此,// 自动转换为浮点数可能更有意义,而不是 /。 - thang
3
“Also”之后的第二部分很有意义(与其他语言的相似之处),但是关于第一部分,Python 3 的整个_重点_是不与 Python 2 向后兼容,而是解决 Python 2 中的一堆问题。足够多的人认为“/”的歧义足以成为一种需要在 Python 3 中修复的语言设计“错误”。这可能是一个有争议的决定,但足够多的人认为这是正确的决定。我也认同这一改变。很高兴我们能达成不同意见的共识。干杯 :) - Ray Toal
我理解Python这样做的原因是因为答案不是#.0的情况,但对于答案是#.0的情况,我并不理解。浮点数1.0与整数1相同,因此当计算的数字是整数并导致浮点数等同于整数时,为什么不只返回或打印一个整数呢?这至少保持了类型的一致性和直观性。如果答案包括非零小数,则应返回浮点数。我使用过的其他语言也是这样工作的(聪明地),它们中没有一个在答案是整数时返回#.0。 - SteveExdia

77

糟糕,立即发现2//2。这将输出一个整数而不是一个浮点数。


1
这似乎对负数不起作用。-1 // 5 返回-1,-5 // 5 返回-1。 - michael.schuett
1
@mschuett:这是可以预料的,与Python 2的结果相同。 - Jonas Byström
1
是的,我进行了更深入的挖掘,并发现了这一点。然而,我想很多人可能并没有意识到这一点,这取决于他们来自哪种语言背景。 - michael.schuett
@JonasByström,被点赞的评论要求澄清并给出澄清,这不是一个提示吗?很难看不出从答案的原始版本中找到一个明显的改进机会。好的答案提供解决方案和解决方案的解释。读者可能会因为这个答案而使用//而不是/,导致依赖于浮点数的代码出现问题,而没有意识到其影响。 - TylerH
1
如果两个除数都是整数,则//运算符仅返回整数。 - eric
显示剩余2条评论

58

Python 2.7和Python 3中的除法运算符行为

在Python 2.7中,默认情况下,除法运算符将返回整数输出。

要以双精度方式获得结果,请将被除数或除数乘以1.0。

100/35 => 2 # Expected is 2.857142857142857
(100*1.0)/35 => 2.857142857142857
100/(35*1.0) => 2.857142857142857

在 Python 3 中

// => used for integer output
/ => used for double output

100/35 => 2.857142857142857
100//35 => 2
100.//35 => 2.0    # Floating-point result if the divisor or dividend is real

4
顺便说一下,不需要乘以1.0。 只要其中一个数字是浮点数就足够了。例如,100/35.0 = 100.0/35 = 2.857142857142857 - Tal J. Levy
3
“//”不是用于整数输出的。 “//”是“floor()”函数对除法结果的运算,如果两个操作数都是整数,则得到一个整数,如果其中至少有一个是浮点数,则得到一个浮点数,以保持类型一致性。 - Olivier

25
The accepted answer already mentions PEP 238. I just want to add a quick look behind the scenes for those interested in what's going on without reading the whole PEP.
Python将像+-*/这样的运算符映射到特殊函数,因此例如a + b等价于
a.__add__(b)

关于Python 2中的除法,只有默认的/,它映射到__div__,结果取决于输入类型(例如intfloat)。
Python 2.2引入了__future__特性division,改变了除法语义如下(PEP 238的TL;DR):
  • /映射到__truediv__,必须“返回除法的数学结果的合理近似值”(引用自PEP 238)
  • //映射到__floordiv__,应该返回/的向下取整结果
在Python 3.0中,PEP 238的更改成为默认行为,并且Python对象模型中不再有特殊方法__div__
如果要在Python 2和Python 3中使用相同的代码,请使用:
from __future__ import division

并遵循PEP 238的语义,保留///

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接