但是为什么Python //
会 Select 向负无穷大进位呢?
我不确定最初做出这一 Select 的the个原因是否在任何地方都有记录(尽管据我所知,它可以在某个地方的政治公众人物中详细解释),但我们肯定能找到各种理由来解释它的意义.
一个原因很简单,就是四舍五入朝着负(或正!)无穷大意味着所有数字都以相同的方式取整,而向零取整则使零变得特别.数学上的说法是四舍五入−∞ 为translation invariant,即满足以下等式:
round_down(x + k) == round_down(x) + k
对于所有实数x
和所有整数k
.例如,四舍五入不等于零:
round_to_zero(0.5 - 1) != round_to_zero(0.5) - 1
当然,也存在其他参数,例如您引用的参数基于与%
运算符(行为)的兼容性(我们希望如何),下面将对此进行详细介绍.
实际上,我想说的是,这里的real个问题是,为什么Python的int()
函数被定义为not,将浮点参数向负无穷大取整,这样m // n
就等于int(m / n)
.(我怀疑是"历史原因".)再说一次,这也没什么大不了的,因为Python至少有math.floor()
个满足m // n == math.floor(m / n)
个.
但我不认为C++的/
与模函数不兼容.在C++中,(m/n)*n + m%n == m
也适用.
没错,但在/
轮接近零的情况下保持这种身份,需要以一种尴尬的方式定义%
为负数.特别是,我们失go 了Python %
的以下两个有用的数学属性:
0 <= m % n < n
表示所有m
和所有正n
;和
(m + k * n) % n == m % n
表示所有整数m
、n
和k
.
这些属性很有用,因为%
的主要用途之一是将数字m
"环绕"到长度n
的有限范围内.
例如,假设我们试图计算方向:假设heading
是我们当前的compass heading度(从正北顺时针方向算起,0 <= heading < 360
度),我们想在转动angle
度后计算新的航向(顺时针转动angle > 0
度,逆时针转动angle < 0
度).使用Python的%
运算符,我们可以简单地计算新标题:
heading = (heading + angle) % 360
这将在所有情况下都有效.
然而,如果我们试图在C++中使用这个公式,它的舍入规则和相应的%
个操作符不同,我们会发现环绕并不总是如预期那样工作!例如,如果我们开始面向西北(heading = 315
)并顺时针旋转90°(angle = 90
),我们最终确实会面向东北(heading = 45
).但如果按逆时针方向try to turn back 90°(angle = -90
),使用C++的%
运算符,我们不会像预期的那样回到heading = 315
,而是回到heading = -45
!
为了使用C++ %
操作符来获得正确的环绕行为,我们需要将公式写入如下:
heading = (heading + angle) % 360;
if (heading < 0) heading += 360;
或作为:
heading = ((heading + angle) % 360) + 360) % 360;
(只有在我们始终能够保证heading + angle >= -360
的情况下,更简单的公式heading = (heading + angle + 360) % 360
才会起作用.)
这是为除法使用非平移不变舍入规则,并因此使用非平移不变%
运算符所付出的代价.