Python选择将整数除法舍入到负无穷大背后的数学原因是什么?
我知道Python//
舍入到负无穷大,而在C++中/
正在截断,舍入到0。
到目前为止我知道的是:
|remainder|
-12 / 10 = -1, - 2 // C++
-12 // 10 = -2, + 8 # Python
12 / -10 = -1, 2 // C++
12 // -10 = -2, - 8 # Python
12 / 10 = 1, 2 // Both
12 // 10 = 1, 2
-12 / -10 = 1, - 2 // Both
= 2, + 8
C++:
1. m%(-n) == m%n
2. -m%n == -(m%n)
3. (m/n)*n + m%n == m
Python:
1. m%(-n) == -8 == -(-m%n)
2. (m//n)*n + m%n == m
但是,为什么Python//
选择向负无穷大取整?我没有找到任何资源来解释这一点,只是找到并听到人们含糊地说:&;因为数学原因。
例如Why is -1/2 evaluated to 0 in C++, but -1 in Python?:
抽象地处理这些事情的人往往会觉得 舍入到负无穷大更有意义(这意味着 与数学中定义的模函数兼容,而不是 意思有点滑稽)。
但我认为C++的/
与模函数不兼容。在C++中,(m/n)*n + m%n == m
也适用。
那么,是什么(数学)原因让Python选择舍入到负无穷大呢?
另请参阅Guido van Rossum's old blog post on the topic。
解决方案
但为什么Python
//
选择舍入为负无穷大?
我不确定最初做出这个选择的原因是否有任何记录(尽管,就我所知,它可以在某个PEP中得到很长的解释),但我们肯定可以想出各种理由来解释它的意义。
一个原因很简单,就是舍入为负(或正!)无穷大意味着所有数字都以相同的方式进行舍入,而向零进行舍入则使零变得特别。这样说的数学方式是,向下舍入到?∞是平移不变量,即它满足等式:
round_down(x + k) == round_down(x) + k
对于所有实数x
和所有整数k
。向零四舍五入不会,因为,例如:
round_to_zero(0.5 - 1) != round_to_zero(0.5) - 1
当然,也存在其他参数,例如您引用的基于与%
运算符(行为的方式)的兼容性的参数-下面将详细介绍。
事实上,我想说真正的问题是,为什么要定义的int()
函数而不是,将浮点参数舍入到负无穷大,以便m // n
等于int(m / n)
。(我怀疑是因为历史原因。)话又说回来,这不是什么大不了的事,因为至少有math.floor()
满足m // n == math.floor(m / n)
。
是正确的,但在将但我认为C++的
/
与模函数不兼容。在C++中,(m/n)*n + m%n == m
也适用。
/
四舍五入到零的同时保留该身份需要以一种尴尬的方式为负数定义%
。特别是,我们失去了以下两个有用的Python%
数学属性:
0 <= m % n < n
全部m
和全部正面n
;和(m + k * n) % n == m % n
适用于所有整数m
、n
和k
。
这些属性非常有用,因为%
的主要用法之一是将数字m
换行到有限的长度范围。
例如,假设我们正在尝试计算方向:假设
heading
是我们当前的compass heading度(从正北开始顺时针计算,其中0 <= heading < 360
),并且我们想要在旋转angle
度后计算新的航向(其中angle > 0
如果我们顺时针转,angle < 0
如果我们逆时针转)。使用Python的%
运算符,我们可以简单地将新标题计算为:
heading = (heading + angle) % 360
这在所有情况下都适用。
然而,如果我们尝试在C++中使用这个公式,它具有不同的舍入规则和相应的不同的%
运算符,我们会发现回绕并不总是像预期的那样工作!例如,如果我们开始朝向西北(heading = 315
),然后顺时针旋转90°(angle = 90
),我们最终确实会朝向东北(heading = 45
)。但如果然后尝试逆时针旋转90°(angle = -90
),使用C++的%
运算符,我们将不会像预期的那样返回到heading = 315
,而是返回到heading = -45
!
要使用C++%
运算符获得正确的回绕行为,我们需要将公式写成如下所示:
heading = (heading + angle) % 360;
if (heading < 0) heading += 360;
或AS:
heading = ((heading + angle) % 360) + 360) % 360;
(更简单的公式heading = (heading + angle + 360) % 360
只有在我们始终保证heading + angle >= -360
的情况下才有效。)
这是您为拥有非平移不变的除法舍入规则以及相应的非平移不变的%
运算符而付出的代价。
相关文章