不止是除法,求余或求模一旦有负数参与,结果可能都有差异。本质在于不同语言使用不同求余规则。
- 向零取整
向 0 方向取最接近精确值的整数,C/ObjC/C++/Rust/C#/Java/Go/Swift/JS/VB/仓颉/PHP/Kotlin 等语言都采用这种方式。- 按此规则,被求模的数值是负数,求模的数值也是负数。
- 向下取整
向负无穷方向取最接近精确值的整数,Python采用这种方式(Python2/3都遵循)。 - 向上取整
向正无穷方向取最接近精确值的整数。
所以问题就简单了:
- C语言
9 / -4 == -2.25, 向0取整得到结果-2,推算9 % -4 == 9 - (-2 * -4) == 1. - Python
9 / -4 == -2.25, 向下取整得到结果-3,推算9 % -4 == 9 - (-3 * -4) ==-3.
标准文档的规定
- C语言C89规定,当除数和被除数有负数时,商和余数的符号是未定义行为。C99开始,此行为被约束为固定行为,即向零取整。
- C89 6.3.5章节:"If either operand is negative. whether the result of the / operator is the
largest integer less than or equal to the algebraic quotient or the smallest integer greater than or equal to the algebraic quotient is implementation-defined." - C99 6.5.5章节:"When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded.”
- C89 6.3.5章节:"If either operand is negative. whether the result of the / operator is the
特殊的求模
- VB 语言用浮点数求模,会先把浮点数转换成整数再求模:
12.5 Mod 4.6 等价于 12 Mod 4, 得到3.
