C++和Python的取模的区别

怎么不一样啊?

现象

1
2
3
4
5
6
7
8
print(8 % 3)
print(4 % 7)
print(-8 % 3)
print(-4 % 7)
print(8 % -3)
print(4 % -7)
print(-8 % -3)
print(-4 % -7)

Python 中,运行以上程序的结果是:

1
2
3
4
5
6
7
8
2
4
1
3
-1
-3
-2
-4

C++ 中,编写看起来意思一样的程序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <iostream>

using namespace std;

int main() {
	cout << 8 % 3 << endl;
	cout << 4 % 7 << endl;
	cout << -8 % 3 << endl;
	cout << -4 % 7 << endl;
	cout << 8 % -3 << endl;
	cout << 4 % -7 << endl;
	cout << -8 % -3 << endl;
	cout << -4 % -7 << endl;
	return 0;
}

然而,两个程序的运行结果不一样。下面是 C++ 程序的结果。

1
2
3
4
5
6
7
8
2
4
-2
-4
2
4
-2
-4

分析

整理数据

整理一下数据,列个表格。

算式 Python 结果 C++ 结果
$8 \bmod 3$ $2$ $2$
$4 \bmod 7$ $4$ $4$
$-8 \bmod 3$ $1$ $-2$
$-4 \bmod 7$ $3$ $-4$
$8 \bmod -3$ $-1$ $2$
$4 \bmod -7$ $-3$ $4$
$-8 \bmod -3$ $-2$ $-2$
$-4 \bmod -7$ $-4$ $-4$

原因

两种语言给出不同的结果的原因是这两种语言执行除法的方式不同。(欧几里得除法:a = b * q + ra 为被除数,b 为除数,q 为商,r 为余数)

  • Python 采用的方法是:向负无穷方向舍入,即让商更小(但需保证 $-|b| \le r \le |b|$)。
  • C++ 采用的方法是:向零舍入,即让商更靠近零(但需保证 $-|b| \le r \le |b|$)。

举个例子

1
2
3
4
5
-8 / 3
Python:
-8 = 3 * -3 + 1
C++:
-8 = 3 * -2 - 2
1
2
3
4
5
4 / -7
Python:
4 = -7 * -1 - 3
C++:
4 = -7 * 0 + 4

拓展

如何让余数变为非负整数

保证余数为非负整数只需 $((a \bmod b) + b) \bmod b$。

使用 Hugo 构建
主题 StackJimmy 设计