为什么计算器 -1 mod 26 = 25,但在 C 或 Java-1 % 26 == -1
中。我需要一个像计算器一样解决它的程序。两者有区别吗?
3 回答
两个答案(25 和 -1)都是有效的。只是不同的系统有不同的约定。
我看到最常见的(在数学中)是:
quotient = floor(x / y)
remainder = x - quotient * y
哪里floor()
是向负无穷大舍入。
这是你的计算器给你的约定。(Mathematica 也使用这种约定。)
我认为大多数编程语言使用的是:
quotient = integerpart(x / y)
remainder = x - quotient * y
其中integerpart()
与 (float -> integer) 强制转换相同。(向零舍入)
一些约定喜欢将余数与操作数之一保持相同的符号。
同样的事情也适用于分隔符的符号。不同的约定是不同的。
“怎么会 ... ?”
模运算有两种常见的定义。Java 选择了一个(“与被除数相同的符号”),计算器实现了另一个;大概是“与除数相同的符号”,尽管您需要做一些实验才能确定。
事实上,关于模运算的 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));
具有负操作数的模运算在不同的语言中是不同的,并且取决于要驱动的语言定义。在 Java 中,Modulus更像是Remainder。
一般来说,如果你想得到一个负输入的负数,那么你可以使用这个:
int r = x % n;
if (r > 0 && x < 0)
{
r -= n;
}
或者,如果您使用的语言在负输入上返回负数并且您更喜欢正数:
int r = x % n;
if (r < 0)
{
r += n;
}
因此,根据您所需要的结果,我建议您使用适当的实现,而不是依赖语言为您计算。
另外,请注意,在 JLS 中权威地描述了 Java 的结果应该是什么:在第 15.17.3 节 - 余数运算符 % 中。他们在那里给出了一个动机(a%b 应该使得 (a/b)*b+(a%b) 等于 a),但正是在 JLS 中包含了该部分才使得结果如此。