【发布时间】:2011-11-20 17:26:30
【问题描述】:
计算器 -1 mod 26 = 25 怎么会用 C 或 Java -1 % 26 == -1。我需要一个像计算器一样解决它的程序。两者有区别吗?
【问题讨论】:
-
你用的是什么计算器?从数学上讲,两个答案都是正确的。另外,在 C 语言中,我相信这里没有指定答案;它也可能是不同的值。
-
C99 要求答案为 -1。
计算器 -1 mod 26 = 25 怎么会用 C 或 Java -1 % 26 == -1。我需要一个像计算器一样解决它的程序。两者有区别吗?
【问题讨论】:
“怎么会……?”
模运算有两种常见的定义。 Java 选择了一个(“与被除数相同的符号”),计算器实现了另一个;大概是“与除数相同的符号”,尽管您需要做一些实验才能确定。
事实上,modulo operation 上的 Wikipedia 页面给出了 4 种不同的运算符定义,它们被不同的编程语言使用。 (并且一些编程语言为您提供了两个具有不同语义的运算符。)
在 C 的情况下,定义取决于您所谈论的 C 标准的版本。对于 ISO C 1999,模运算符遵循与 Java 相同的定义。对于早期版本的 C 标准,% 的语义依赖于实现
“这两者有区别吗?”
显然有!
“我需要一个像计算器一样解决问题的程序。”
随意写一篇:-)。
但是,如果您只想知道如何在 Java 中获得“与除数相同的符号”形式的模数,这里有一种方法:
int otherModulus = (a % b) + (a < 0 ? b : 0); // works for b > 0.
int otherModulus = (a % b) + // works for b != 0
(b > 0 ? (a < 0 ? b : 0) : (a > 0 ? -b : 0));
【讨论】:
两个答案(25 和 -1)都是有效的。只是不同的系统有不同的约定。
我看到的最常见的(在数学中)是:
quotient = floor(x / y)
remainder = x - quotient * y
floor() 是向负无穷舍入。
这是您的计算器提供给您的约定。 (Mathematica 也使用这种约定。)
我认为大多数编程语言使用的是:
quotient = integerpart(x / y)
remainder = x - quotient * y
integerpart() 与 (float -> integer) 类型转换相同。 (向零舍入)
一些约定喜欢将余数与操作数之一保持相同的符号。
同样的事情也适用于分隔符的符号。不同的约定是不同的。
【讨论】:
具有负操作数的模运算在不同的语言中是不同的,并且取决于要驱动的语言定义。在 Java 中,Modulus 更像是 Remainder。
一般来说,如果你想为负输入得到一个负数,那么你可以使用这个:
int r = x % n;
if (r > 0 && x < 0)
{
r -= n;
}
或者,如果您使用的语言在负输入上返回负数并且您更喜欢正数:
int r = x % n;
if (r < 0)
{
r += n;
}
因此,根据您所需的结果,我建议您使用适当的实现,而不是依赖语言为您计算。
另外,请注意,对于 Java 的结果应该是什么,在 JLS: in the section 15.17.3 - Remainder Operator % 中有权威性的描述。他们在那里给出了动机(a%b 应该使得 (a/b)*b+(a%b) 等于 a),但正是在 JLS 中包含该部分才使结果如此。
【讨论】: