C 语言规定 a / b 的值 q 是 a 除以 b 向零取整,而 a % b 是满足 a = qb + r (带余除法恒等式)惟一的 r 。
数论中常见的定义是 0 <= r < |b|,此时 q 的数值并不是 a 除以 b 向零取整,而是向下取整,比如
C 语言:
-1 = 0*3 + (-1)
1 = 0*(-3) + 1
数论:
-1 = (-1)*3 + 2
1 = (-1)*(-3) + 2
带余除法恒等式相当重要且自然,如果丧失它则扩展欧几里得算法 [给定 a, b 计算 x, y 使 ax+by=(a,b)] 会很难写对。以下三者不可兼得:
1. 带余除法恒等式
2. 对一切 a 不是 int 最小值且 b 不是 0 ,成立 -(a / b) == (-a) / b 且 -a / b == 0 - a / b ,即“向零取整”
3. a % b 永远是非负数
值得注意的是 Python 也没有完全采用数论中常见的定义,因为 Python 里 a % b 的符号是 0 或者和 b 相同(整数的情况),而不是永远非负。
C 和 Python 都不是“常见数论教材”纯粹的。数学上对余数的选择没有某种必然的对错,通常选 (-b, b) 里的任何数都不会导致常见的算法(如欧几里得算法)无法继续。
C 语言选择向零取整、保持带余除法恒等式,虽然 a % b 可能有负数,但是保证了
-a/b
(-a)/b
(0-a)/b
-(a/b)
0-(a/b)
0-a/b
的计算结果都相同(假设 a 不是 int 最小值且 b 不是 0 )。而在 Python 里面,对于整数 a,b ,表达式
-a//b
(-a)//b
(0-a)//b
和
-(a//b)
0-(a//b)
0-a//b
的两组结果分别相同,但组间可以不同,不同当且仅当 a/b 是负非整数。 |