我知道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 //会 Select 向负无穷大进位呢?我没有找到任何资源来解释这一点,只是找到并听到人们含糊其辞地说:"for mathematics reasons".

例如,在100中:

抽象地处理这些事情的人往往会觉得

但我不认为C++的/与模函数不兼容.在C++中,(m/n)*n + m%n == m也适用.

那么Python Select 向负无穷进位的(数学)原因是什么呢?


另见第Guido van Rossum's old blog post on the topic页.

推荐答案

但是为什么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 %的以下两个有用的数学属性:

  1. 0 <= m % n < n表示所有m和所有正n;和
  2. (m + k * n) % n == m % n表示所有整数mnk.

这些属性很有用,因为%的主要用途之一是将数字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才会起作用.)

这是为除法使用非平移不变舍入规则,并因此使用非平移不变%运算符所付出的代价.

Python-3.x相关问答推荐

如何在Django中创建两个不同权限的用户?

如何从Django连接到Neo4J s AuraDB(免费层)?'

使用Python请求从特定URL下载图像时出错

我没有';无法理解此TemplateDoesNotExist错误

visual studio代码窗口中未激活虚拟环境11

在 sum() 中将字符串转换为 int (或 float)

可以在 Python 的上下文管理器中调用 sys.exit() 吗?

Python,Web 从交互式图表中抓取数据

!date 的命令无法从 jupyter notebook 运行

为什么 Sympy 不能解决我的非线性系统? Python 解释器一直在执行,直到我终止进程

Python defaultdict 在获取时返回 None,尽管使用默认值初始化

根据另一列值对多个数据框列进行分组

机器学习实验笔记本的工作区 url

如何将数据框中的每一行转换为具有属性的 node ?

解包时是否可以指定默认值?

Pytorch 的随机 Select ?

运行 PyCharm 测试时如何解决django.core.exceptions.ImproperlyConfigured:找不到 GDAL 库?

在计算之前删除包含某些值的组合

Python:在 map 对象上调用列表两次

python asyncio add_done_callback 与 async def