简体   繁体   English

C 正数 arguments 的余数/模运算符定义

[英]C remainder/modulo operator definition for positive arguments

I found a function in a program I am supposed to fix that has a mod function defined:我在一个我应该修复的程序中找到了一个 function,它定义了一个mod function:

int mod(int a, int b)
{
  int i = a%b;
  if(i<0) i+=b;
  return i;
}

I was told that a and b will always be positive by the way...有人告诉我,顺便说一句, ab将永远是积极的......

Huh?嗯? if(i<0) ? if(i<0)

The argument is, that论据是

the result of the modulo operation is an equivalence class, and any member of the class may be chosen as representative模运算的结果是等价的 class,可以选择 class 的任何成员作为代表

And only as an afterthought并且只是作为事后的想法

...; ...; however, the usual representative is the least positive residue, the smallest nonnegative integer that belongs to that class, ie the remainder of the Euclidean division.然而,通常的代表是最小的正残差,最小的非负 integer 属于那个 class,即欧几里得除法的余数。 However, other conventions are possible.然而,其他约定也是可能的。

That means that 6 % 7 could return 6 (so far so good), but also -1 .这意味着6 % 7可以返回6 (到目前为止还不错),但也可以返回-1 Hrm... really?嗯……真的吗? (Lets ignore the fact that the presented implementation does not handle all cases.) (让我们忽略所呈现的实现不能处理所有情况的事实。)

I know that it is mathematically true that the modulo operation is like this.我知道从数学上讲,模运算是这样的。 But then someone else told me that the C % does in fact "not implement the modulo operator but the remainder".但是后来有人告诉我, C %实际上“没有实现模运算符,而是实现了余数”。

So, how does C define the % operator?那么,C 是如何定义%运算符的呢?

In the C-Draft I only find在 C-Draft 我只发现

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.在这两种操作中,如果第二个操作数的值为零,则行为未定义。

Does this mean, that 6 % 7 is always 6 ?这是否意味着6 % 7总是6 Or can it be -1 , too?或者也可以是-1

According to the standard:根据标准:

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 .如果商 a/b 是可表示的,则表达式(a/b)*b + a%b应等于a [ISO/IEC 9899:2011: 6.5.5] [ISO/IEC 9899:2011: 6.5.5]

This means that the sign of a is preserved in the modulo.这意味着a的符号保留在模中。

 17 %  3  ->  2
 17 % -3  ->  2
-17 %  3  -> -2
-17 % -3  -> -2

So no, 6%7 cannot be -1 because the reminder has to have the same sign of the dividend.所以不, 6%7不能是-1 ,因为提醒必须具有相同的股息符号。

Forever:永远:

  • a == (a/b)*b + a%b
  • abs(a%b) < abs(b)
  • if a and b are positive, a % b is positive.如果ab为正,则a % b为正。

Since C99,自C99以来,

  • a/b == trunc(a/b)
  • a%b is either 0 or has the sign of a . a%b0或有符号a

Thinking that 6 % 7 could be -1 is probably due to missing the fact that the result for a and b positive has always been guaranteed and missing the change in C99.认为6 % 7可能是-1可能是由于错过了ab阳性的结果始终得到保证的事实,并且错过了 C99 中的变化。

Does this mean, that 6 % 7 is always 6?这是否意味着 6 % 7 总是 6? Or can it be -1, too?或者也可以是-1?

According to this documention :根据这个文件

Remainder

The binary operator % yields the remainder of the division of the first operand by the second (after usual arithmetic conversions).二元运算符 % 产生第一个操作数除以第二个操作数的余数(在通常的算术转换之后)。

[...] [...]

when the type after usual arithmetic conversions is an integer type, the result is the algebraic quotient (not a fraction), rounded in implementation-defined direction (until C99)truncated towards zero (since C99)当通常算术转换后的类型是 integer 类型时,结果是代数商(不是分数),在实现定义的方向四舍五入(直到 C99)截断为零(自 C99 起)

So 6 / 7 will be 0 , and 6 % 7 will be 6 - 0 , which is 6 .所以6 / 7将是0 ,而6 % 7将是6 - 0 ,即6

The claim about modulo operations and equivalence classes is interesting, that's not how it works in C (and most other programming languages).关于模运算和等价类的说法很有趣,这不是它在 C(和大多数其他编程语言)中的工作方式。

Besides, even if that were the case, wouldn't -8 be in the same equivalence class?此外,即使是这种情况, -8也不会等同于 class 吗? Then if(i<0) i+=b;那么if(i<0) i+=b; wouldn't solve the problem.不会解决问题。

But then someone else told me that the C % does in fact "not implement the modulo operator but the remainder".但是后来有人告诉我, C % 实际上“没有实现模运算符,而是实现了余数”。

Good point.好点子。 In the documentation that I linked, it is called the "Remainder".在我链接的文档中,它被称为“Remainder”。

There are at least three different ways of defining the division and remainder algorithms when one number or the other might be negative.当一个数字或另一个可能为负时,至少有三种不同的方法来定义除法和余数算法。 (See this Wikipedia article -- and particularly the nice picture there -- for more details.) (有关更多详细信息,请参阅此 Wikipedia 文章——尤其是那里的精美图片。)

But if you know you're dividing a positive number by a positive number, there's no ambiguity whatsoever.但是,如果您知道将正数除以正数,则没有任何歧义。 All three definitions of division and remainder say that if you're dividing a positive number by a positive number, you get a positive quotient and a positive remainder.除法和余数的所有三个定义都表明,如果将正数除以正数,则会得到正商和正余数。

Of the three options there, C uses the one called "truncating division".在那里的三个选项中,C 使用一种称为“截断除法”的选项。 But, again, for positive numbers, it doesn't make any difference.但是,同样,对于正数,它没有任何区别。 (Once upon a time, it was up to the compiler whether it used truncating or "Euclidean" division, but things settled down on just the one definition, several revisions of the C Standard ago.) (曾几何时,是否使用截断或“欧几里得”除法取决于编译器,但事情只解决了一个定义,即之前 C 标准的几个修订版。)

Does this mean, that 6 % 7 is always 6 ?这是否意味着6 % 7总是6 Or can it be -1 , too?或者也可以是-1

Yes, 6 % 7 is always 6 (in C, and under any of the three definitions).是的, 6 % 7始终为 6(在 C 中,以及在三个定义中的任何一个下)。

See also this epic, related question .另请参阅这个史诗般的相关问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM