c - C中模运算的规则是什么?

标签 c modulus

在早期的类(class)中,我被教导 n % d = r 并将其视为 n = d*q + r,其中 d 是除数,q 是商,r 是余数(注意余数永远不能为负)。

例如,-111 mod 1110,因为 -111 = -11*-11 + 10(与-111 = -11*10 -1,看看这会给我们带来负余数)。

但是,当打印-111 % 11的结果时,-1是结果而不是10。为什么?这在技术上不是错误的吗?

最佳答案

简答:

标准保证 (a/b)*b + a%b 等于 a

在 C99 中,除法 / 的结果将被截断为零。 % 运算符的结果是确定的,在本例中为 -1

在 C89 中,除法 / 的结果可以被截断为负操作数。所以 % 运算符的结果也是机器相关的。

长答案:

来自 C99 6.5.5

5 The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined.

6 When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.

在同一页上的脚注解释了 / 是如何工作的,它说:

This is often called ‘‘truncation toward zero’’.

按照这个规则,-111/11只能是-10,不能是1。因为(a/b)*b + a%b 必须等于 a,我们有 -111 % 11-1

然而,K&R Chapter 2.5给出了不同的答案:

The direction of truncation for / and the sign of the result for % are machine-dependent for negative operands, as is the action taken on overflow or underflow.

据此,-110 都可以是合法结果。

原因在C89 3.3.5:

When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a .

原来是C89到C99的变化。

C99 Rationale 6.5.5 提供了一些历史原因:

In C89, division of integers involving negative operands could round upward or downward in an implementation-defined manner; the intent was to avoid incurring overhead in run-time code to check for special cases and enforce specific behavior. In Fortran, however, the result will always truncate toward zero, and the overhead seems to be acceptable to the numeric programming community. Therefore, C99 now requires similar behavior, which should facilitate porting of code from Fortran to C. The table in §7.20.6.2 of this document illustrates the required semantics.

这是 §7.20.6.2 中的表格:

numer denom quot rem
 7      3    2    1
–7      3   –2   –1
 7     –3   –2    1
–7     –3    2   –1

关于c - C中模运算的规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17461486/

相关文章:

c++ - 为什么短路模数在 Release模式下不正确?

c++ - 与 fmod() 结果比较返回 false

c - GCC 无法在包含的库中找到头文件

c++ - 为什么指向整数的指针递增 4 个字节?

c - 使用 setjmp 和 longjmp 时,jmp_buf 中的实际内容是什么?

c - linux 汇编程序如何乘除 64 位数字?

JavaScript 在每 % 行做一些事情

c - 字节打印和写入

c++ - 是否可以在不必计算 A/B 的情况下有效地计算 A % B?

algorithm - 快速计算 n! mod m 其中 m 是素数?