某些语言是否允许负模数?

eve*_*sor 9 c java math modulus

我很好奇这些语言(Java,C ...)忽略了模数运算的数学定义.

在模块操作中返回负值的重点是什么(根据定义,应该总是返回正数)?

Jon*_*eet 7

至少在Java中,它不是模数运算符 - 它是余数运算符.

我认为选择这种方式的原因是为了使这种关系起作用(来自JLS):

二进制数字提升(第5.6.2节)后整数操作数的余数运算产生一个结果值,使得(a/b)*b +(a%b)等于a.即使在特殊情况下,这种同一性仍然存在,即被除数是其类型的最大可能量值的负整数,且除数为-1(余数为0).根据这个规则可以得出,只有当被除数为负时,余数运算的结果才是负数,只有当被除数为正时才能为正; 而且,结果的大小总是小于除数的大小.

作为定义的一部分,这种平等关系似乎是合理的.如果你将除法截断为零作为给定,那么就会留下负余数.

  • @JerryCoffin:实际上我相信你是对的 - 由于整数溢出,'INT_MIN/-1`*可能*未定义,但似乎余数应该仍为零.但是我可以通过该操作将`gcc`改为`SIGFPE` ... (2认同)

Mat*_*ell 6

来自维基百科(我的重点):

给定两个正数,a(被除数)和n(除数),模n(缩写为mod n)可以被认为是a除以a的余数.例如,表达式"5 mod 4"将评估为1,因为5除以4会留下1的余数,而"9 mod 3"将评估为0,因为9除以3会使余数为0; 在乘以3次3后,没有什么可以从9中减去.(注意,用计算器进行除法不会显示此操作引用的结果,商将表示为小数.)当a或者n是负数,这个天真的定义分解,编程语言在定义这些值方面有所不同.尽管通常在a和n都是整数的情况下执行,但许多计算系统允许其他类型的数字操作数.n的整数模数的范围是0到n-1.(n mod 1总是0; n mod 0未定义,可能导致计算机编程语言中的"除以零"错误)参见模拟算术在数论中应用的较旧和相关的惯例.

  • 我总是学习的除法"n/d"的代数定义是`n = qd + r`,其中`0≤r<d`.:-) (2认同)

dan*_*n04 6

我怀疑余数运算符是故意设计成具有那些语义的,我同意这些语义不是很有用。(你有没有写过一个日历程序,在这个纪元之前的日期显示星期日、反星期六、反星期五、...、反星期一?)

相反,负余数是整数除法定义方式的副作用。

A rem B := A - (A div B) * B
Run Code Online (Sandbox Code Playgroud)

如果A div B定义为trunc(A/B),您将获得 C 的%运算符。如果A div B定义为floor(A/B),您将获得 Python 的%运算符。其他定义也是可能的。

所以,真正的问题是:

为什么 C++、Java、C# 等使用截断整数除法?

因为这就是 C 的方式。

为什么 C 使用截断除法?

最初,C 没有指定/应该如何处理负数。它留给了硬件。

在实践中,每个重要的 C 实现都使用截断除法,因此在 1999 年这些语义正式成为 C 标准的一部分。

为什么硬件使用截断除法?

因为在无符号除法方面更容易(=更便宜)实现。您只需计算abs(A) div abs(B)并翻转符号 if (A < 0) xor (B < 0)

如果余数不为零,则底除法具有从商中减去 1 的附加步骤。