java如何用负数进行模数计算?

Posted

技术标签:

【中文标题】java如何用负数进行模数计算?【英文标题】:How does java do modulus calculations with negative numbers? 【发布时间】:2011-05-23 03:47:52 【问题描述】:

我做模数错了吗?因为在 Java 中 -13 % 64 的计算结果为 -13 但我想得到 51

【问题讨论】:

@Dan 即使没有静态 main void ...我看到了代码。 我得到 -13 & 64 == -13 如何你的 ratehr 比 -13 高 51。 你根本没有做模数。 Java 中没有模运算符。 % 是余数运算符。 令人困惑的问题:正如其他人所说,Java 8 给出了 -13。您应该使用哪个 Java 版本? 【参考方案1】:

负数模数的两种定义都在使用 - 一些语言使用一种定义,而另一些则使用另一种。

如果你想为负输入得到一个负数,那么你可以使用这个:

int r = x % n;
if (r > 0 && x < 0)

    r -= n;

同样,如果您使用的语言在负输入上返回负数并且您更喜欢正数:

int r = x % n;
if (r < 0)

    r += n;

【讨论】:

如果 n 为负数,这将不起作用。如果您使用 Java 7 语言规范(第 15.17.3 节)中的相同示例:(-5) % (-3) = -2。添加 -3 将不起作用。如果你想确保值是正的,你应该添加 n 的绝对值。 在 Java 中负模不会改变任何东西,如果你仍然使用 Abs(),只需写 r = x % abs(n)。我不喜欢 if 语句,我宁愿写 r = ((x%n) + n) % n。关于 2 模(2、4、8、16 等)的幂和肯定答案,请考虑二进制掩码 r = x & 63。 在 Java 的上下文中(根据问题标签),这个答案本质上是“错误的”。给定表达式x % y,A) 如果x 为负,则余数为负,即x % y == -(-x % y)。 B)y 的符号无效,即x % y == x % -y【参考方案2】:

因为“数学上”两者都是正确的:

-13 % 64 = -13 (on modulus 64)  
-13 % 64 = 51 (on modulus 64)

Java 语言开发人员必须选择其中一个选项,他们选择了:

结果的符号等于被除数的符号。

在 Java 规范中这样说:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.3

【讨论】:

问题是“为什么当我期待-13 时,Java 给了我-13 % 64 = 51?”。 @pascal:java 为您提供了正确的数学定义以及它的实现方式,而不是您所期望的。 Java 8 中提供了数学上健全的行为:Math.floorMod 15.17.3. Remainder Operator % 示例中的某些内容尚不清楚。 int result = (-5) % 3; 给出 -2。 int result = (-3) % 5; 给出-3。一般来说,int result = (-a) % b; 在 |-a| 时给出正确答案。 > 乙。为了在 |-a| 时得到正确的结果int result = ((-a) % b) + b; 用于负 a 或 int result = (((-a) % b) + b) % b; 用于正或负 a @Caner 这个我没看懂,怎么可能是一样的?【参考方案3】:

您确定您正在使用 Java 工作吗?因为Java按预期给出了-13 % 64 = -13。分红的标志!

【讨论】:

【参考方案4】:

您的结果对于 Java 是错误的。 请提供一些背景信息(您的程序、实现和 Java 版本)。

来自Java Language Specification

15.17.3 余数运算符 % [...] 在二进制数值提升(第 5.6.2 节)之后,整数操作数的余数运算产生一个结果值,使得 (a/b)*b+(a%b) 等于 a。
15.17.2 除法运算符 / [...] 整数除法向 0 舍入。

由于 / 向零舍入(结果为零),在这种情况下 % 的结果应该是负数。

【讨论】:

15.17.3. Remainder Operator % 示例中的某些内容尚不清楚。 int result = (-5) % 3; 给出 -2 int result = (-3) % 5; 给出 -3 一般来说,int result = (-a) % b; 在 |-a| 时给出正确答案> b 为了得到正确的结果当|-a| int result = ((-a) % b) + b; 用于负 a 或 int result = (((-a) % b) + b) % b; 用于正或负 a。 您的评论很不清楚。该部分定义正确的结果,并且示例与该定义一致。对于您的示例(-3) % 5,根据定义,正确的结果是-3,Java 的正确实现应该产生该结果。 我想我没有正确解释自己。当 |-a|(-3)%5 确实给出了-3,如果我们想要正余数,我们应该给它加 5,然后结果将是2【参考方案5】:

你可以使用

(x % n) - (x < 0 ? n : 0);

【讨论】:

@ruslik 你也可以这样做:((x % k) + k) % k。 (虽然你的可能更具可读性。) @JohnKurlak 你的版本是这样工作的:4 % 3 = 1 OR 4 % -3 = -2 OR -4 % 3 = 2 OR -4 % -3 = -1 但是来自 ruslik像这样工作:4 % 3 = 1 OR 4 % -3 = 1 OR -4 % 3 = -4 OR -4 % -3 = 2 @Joschua 感谢您指出这一点。当您希望模数结果在 [0, sign(divisor) * divisor) 而不是 [0, sign(dividend) * divisor) 的范围内时,我的代码很有帮助。【参考方案6】:

您的答案在***中: modulo operation

它说,在 Java 中,模运算的符号与除数相同。并且由于我们谈论的是除法运算的其余部分,所以它在您的情况下返回-13,因为-13/64 = 0。-13-0 = -13。

编辑:对不起,误解了你的问题......你是对的,java应该给-13。能否提供更多周边代码?

【讨论】:

【参考方案7】:

具有负操作数的模运算由语言设计者定义,他们可能会将其留给语言实现,他们可能会将定义推迟到 CPU 架构。

我找不到 Java 语言定义。 感谢 Ishtar,Remainder Operator % 的 Java 语言规范说结果的符号与分子的符号相同。

【讨论】:

【参考方案8】:

要克服这个问题,您可以将 64(或任何您的模数基数)添加到负值,直到它为正

int k = -13;
int modbase = 64;

while (k < 0) 
    k += modbase;


int result = k % modbase;

结果仍将属于同一个等价类。

【讨论】:

【参考方案9】:

x = x + m = x - m 模数为 m。 所以 -13 = -13 + 64 在模数 64-13 = 51 在模数 64。 假设Z = X * d + r,如果0 &lt; r &lt; X 则在除法Z/X 中我们调用r 余数。Z % X 返回Z/X 的余数。

【讨论】:

【参考方案10】:

mod 函数定义为一个数超过不大于该数的除数的最大整数倍的量。所以在你的情况下

-13 % 64

不超过-13的64的最大整数倍是-64。现在,当你从 -64 中减去 -13 时,它等于 51 -13 - (-64) = -13 + 64 = 51

【讨论】:

【参考方案11】:

在我的 Java JDK 1.8.0_05 -13%64=-13 版本中

你可以试试 -13-(int(-13/64)) 换句话说,将除法转换为整数以摆脱小数部分 然后从分子中减去 所以 numerator-(int(numerator/denominator)) 应该给出正确的余数和符号

【讨论】:

【参考方案12】:

在 Java 最新版本中,您会得到 -13%64 = -13。答案总是有分子符号。

【讨论】:

此更改是在哪个版本中进行的? 在 java 7 中明确提到 mod 将有分子符号 :) @NightShadeQueen 从未改变。【参考方案13】:

根据 JLS 的第 15.17.3 节,“在二进制数值提升之后,整数操作数的余数运算会产生一个结果值,使得 (a/b)*b+(a%b) 等于 a。 这个恒等式甚至在被除数是其类型的最大可能量级的负整数并且除数是-1(余数是0)的特殊情况下也成立。"

希望对您有所帮助。

【讨论】:

【参考方案14】:

在这种情况下,我认为 Java 不会返回 51。我在 Mac 上运行 Java 8,我得到:

-13 % 64 = -13

程序:

public class Test 
    public static void main(String[] args) 
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    

【讨论】:

@XaverKapeller,不!许多人指出,从数学上讲-13和51是正确的。在Java中,-13是预期的答案,这也是我得到的,所以我不知道提交者是如何得到51的,这很神秘。有关上下文的模式详细信息有助于正确回答此问题。 @Xaver Kapeller:51 和 -13 怎么可能都是正确的? Java 只会返回一个值.. @XaverKapeller 一个记录 Java 实际操作的答案怎么可能是错误的? @EJP 我想 3 年前当我写这篇文章时,我愚蠢到更重视数学准确性,而不是 java 如何处理这个问题的简单现实。感谢您提醒我删除我的愚蠢评论:D

以上是关于java如何用负数进行模数计算?的主要内容,如果未能解决你的问题,请参考以下文章

如何用零替换数组中的所有负数[重复]

如何用加法实现减法

Java基本语法--运算符

为啥 C++ 使用模数时输出负数?

C ++中带负数的模数[重复]

在计算机中,为啥负数要用补码的形式表示呢?(图文并茂版)