为什么除法会被舍入为整数?

138

我试图将从-100到0的一组数字归一化为10到100的范围,并且遇到了问题,但是我注意到即使没有任何变量,它也不会如我所期望的那样求值:

>>> (20-10) / (100-10)
0

浮点数除法也不起作用:

>>> float((20-10) / (100-10))
0.0

如果除法运算符的任一操作数被强制转换为浮点数,它将起作用:

>>> (20-10) / float((100-10))
0.1111111111111111

在第一个例子中,每个操作数都被计算为整数,这意味着最终答案将被转换为整数。由于0.111小于0.5,所以它会四舍五入为0。在我看来,这不太透明,但我想那就是这样。

请解释一下原因?


3
Adam,我仍然不喜欢你的解释。第一个例子是整数除法,它只返回0。第二个例子的括号使用错误,无法达到你想要的效果。 - President James K. Polk
@GregS 第一个例子是问题所在。第二个例子是解释性的,是在第一个问题之后编写的。下面所有的答案都很好地解释了这个问题,特别是 @KennyTM 的回答。需要注意的是,我的原始问题只在 Python 2.x 上存在,而不是 3.x。这种行为的变化有点令人不安,但现在我知道了,我会使用 from future import division 并使用 3.x 的行为。干杯。 - Adam Nelson
1
Adam,请纠正你最后的编辑。右侧没有什么特别之处;为了使除法成为浮点数,分子或分母(或两者)必须是浮点数。如果你认为在文档中读到右侧需要是浮点数,那么要么文档措辞不当应该进行更正,要么你误解了它。也许你看到了一个例子,然后推断出了一个规则? - tzot
"浮点数除法也不起作用:"这个例子不是“浮点数除法”,这就是问题所在。在这里,float调用,并且无论何时调用某些东西,都会在调用之前评估参数。float只看到一个整数,无法推断产生该整数的计算结果。" - Karl Knechtel
我将此关闭为重复项,因为答案(包括被接受的答案)没有解释 Python 2.x 中设计决策的原因(由于主要基于个人观点,这可能会被视为离题)。链接的重复项是规范,解释了如何编写代码以获得浮点结果,这似乎是 OP 想要的所有内容(尽管 OP 已经有了一个可行的解决方案)。 - Karl Knechtel
13个回答

247

您正在使用Python 2.x版本,其中整数除法将截断而不是变成浮点数。

>>> 1 / 2
0

你应该将它们中的一个声明为 float 类型:

>>> float(10 - 20) / (100 - 10)
-0.1111111111111111

或者使用from __future__ import division,它会强制/采用Python 3.x的行为,始终返回一个浮点数。

>>> from __future__ import division
>>> (10 - 20) / (100 - 10)
-0.1111111111111111

10
如果你使用 from __future__ import division,则可以通过使用两个斜杠(例如 1 // 2 将得到 0)来获得旧的 C 风格的除法行为。参见 Pep 238 Changing the Division Operator - User
1
@User 不需要从__future__导入。在Python 2和3中,//默认引用__floordiv__() - Janosh
@Casimir 他们的意思是,如果你需要地板除法,它是可用的。你不必被限制在__future__.division的行为上。 - wjandrea

21

你输入的是整数,因此Python返回给你的也是整数,点击链接了解更多关于Python二进制算术运算的细节。

>>> 10 / 90
0

如果你在这之后将它转换为float类型,那么四舍五入已经完成,换句话说,0整数总是会变成0浮点数。

如果你在除法的两边使用float类型,Python会给你期望中的答案。

>>> 10 / 90.0
0.1111111111111111

因此,在您的情况下:

>>> float(20-10) / (100-10)
0.1111111111111111
>>> (20-10) / float(100-10)
0.1111111111111111

13
在Python 2.7中,如果输入是整数,则/操作符是整数除法:
>>>20/15
1

>>>20.0/15.0
1.33333333333

>>>20.0/15
1.33333333333

在Python 3.3中,即使输入为整数,/运算符也会执行浮点数除法。
>>> 20/15
1.33333333333

>>>20.0/15
1.33333333333

在Python 3中进行整数除法,我们将使用//运算符。

//运算符在Python 2.7和Python 3.3中均为整数除法运算符。

在Python 2.7和Python 3.3中:

>>>20//15
1

现在,看一下比较结果

>>>a = 7.0/4.0
>>>b = 7/4
>>>print a == b

对于上面的程序,在Python 2.7中输出为False,而在Python 3.3中输出为True。

在Python 2.7中,a = 1.75且b = 1。

在Python 3.3中,a = 1.75且b = 1.75,这是因为/表示浮点数除法。


11

在进行除法之前,你需要将它转换为浮点数。即:

float(20 - 10) / (100 - 10)

4
@Adam Nelson:对我来说运行正常。请检查您的括号。 - Fred Larson
实际上,我错了 - 但是在查看文档后,应该先将右侧转换。 - Adam Nelson
11
没问题,@Adam的意思是无论哪一面先开始都可以。 - kennytm

8
这与您使用的Python版本有关。基本上它采用了C的行为:如果您将两个整数相除,结果将向下舍入为整数。还要记住,Python从左到右执行操作,在进行类型转换时起作用。
例如:由于这是我进行算术运算时经常出现的问题(是否应该转换为浮点数以及哪个数字),因此从这个角度提供一个示例。
>>> a = 1/2/3/4/5/4/3
>>> a
0

当我们对整数进行除法运算时,不出所料会进行向下取整。
>>> a = 1/2/3/4/5/4/float(3)
>>> a
0.0

如果我们将最后一个整数强制转换为浮点数,仍然会得到零,因为当我们的数字被除以浮点数时,它已经因为整数除法而变成了零。
>>> a = 1/2/3/float(4)/5/4/3
>>> a
0.0

与上述情况相同,但将浮点类型转换略微靠近左侧。

>>> a = float(1)/2/3/4/5/4/3
>>> a
0.0006944444444444445

最后,当我们将第一个整数强制转换为浮点数时,结果是期望的,因为从第一个除法开始,即最左边的除法,我们使用浮点数。
附加1:如果您正在尝试回答如何改进算术计算,请查看this 附加2:请注意以下情况:
>>> a = float(1/2/3/4/5/4/3)
>>> a
0.0

4
使用小数点将数字转换为浮点数,可以使它默认为浮点数。
>>> 1 / 2
0

>>> 1. / 2.
0.5

2

将其中至少一个数设为浮点型,这样就会进行浮点除法而不是整数除法:

>>> (20.0-10) / (100-10)
0.1111111111111111

将结果转换为浮点数太晚了。

1
在Python中,cv2没有更新除法计算。因此,您必须在程序的第一行中包含from __future__ import division

0

个人而言,我更喜欢在开头插入1. *。因此,表达式会变成这样:

1. * (20-10) / (100-10)

我经常对一些公式进行除法运算,比如:

accuracy = 1. * (len(y_val) - sum(y_val)) / len(y_val)

因此,无法像20.0那样简单地添加.0。在我的情况下,使用float()可能会失去一些可读性。


0
在Python 3中,“//”运算符适用于整数和浮点数参数的地板除法。但是,如果其中一个参数为浮点数,则运算符“/”将返回一个浮点值(这类似于C ++)。
例如:
# A Python program to demonstrate the use of
# "//" for integers
print (5//2)
print (-5//2)

输出:

2
-3



# A Python program to demonstrate use of
# "/" for floating point numbers
print (5.0/2)
print (-5.0/2)

输出:

2.5
-2.5

参考:https://www.geeksforgeeks.org/division-operator-in-python/


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