Java如何用负数计算模数?


92

我的模数做错了吗?因为在Java -13 % 64中应该进行评估,-13但是我得到了51


102
@Dan即使没有静态main void,也可以看到代码。
Joris Meys 2010年

22
我得到-13&64 == -13
Grodriguez 2012年

7
与-13相比,您获得51 ratehr的效果如何
2014年

3
您根本没有做模数。Java中没有模运算符。%是余数运算符。
罗恩侯爵,

3
令人困惑的问题:正如其他人所说,Java 8给出-13。您应该使用哪个Java版本?
JanŻankowski17年

Answers:


103

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

如果要为负输入获得负数,则可以使用以下方法:

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

同样,如果您使用的是在否定输入中返回负数的语言,并且您希望使用正数:

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

3
如果n为负,则效果不好。如果您使用Java 7 Lang Spec(第15.17.3节)中的相同示例:(-5)%(-3)= -2。添加-3将不起作用。如果要确保该值为正,则应添加n的绝对值。
partlov

6
在Java中,负模不会改变任何内容,如果仍然使用Abs(),则只需写r = x%abs(n)。我不喜欢if语句,我宁愿写r =((x%n)+ n)%n。关于2模(2,4,8,16等。)和阳性应答的功率,考虑二元掩模R = X&63.
Fabyen

3
在Java上下文中(根据问题标签),该答案本质上是“错误的”。给定表达式x % yA)如果x为负,则其余为负,即x % y == -(-x % y)。B)y无效的迹象,即x % y == x % -y
波希米亚语

71

由于“数学上”都正确:

-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


8
问题是“为什么Java -13 % 64 = 51在我期望的时候给我-13?”。
Pascal Cuoq 2010年

5
@pascal:java为您提供了正确的数学定义以及实现该目标的方式,而这并非您期望的。

9
Java 8中提供了数学上合理的行为:Math.floorMod
Jesse Glick,

1
他们的15.17.3。余下的运算符%示例尚不清楚。int result = (-5) % 3;给出-2。int result = (-3) % 5;给出-3。通常,int result = (-a) % b;在| -a |时给出正确的答案 > b。为了获得适当的结果,当| -a | <b我们应该包裹除数。int result = ((-a) % b) + b;表示负数a或int result = (((-a) % b) + b) % b;表示正数或负数
Oz Edri

@Caner我听不懂,怎么可能一样呢?
Kishore Kumar Korada '19

20

您确定使用Java吗?因为Java给出预期的-13%64 = -13。分红的迹象!


15

对于Java,您的结果是错误的。请提供一些上下文信息(您的程序,实现和Java版本)。

来自Java语言规范

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

由于/被四舍五入为零(结果为零),因此在这种情况下%的结果应为负。


他们的15.17.3。余下的运算符%示例尚不清楚。int result = (-5) % 3;给-2 int result = (-3) % 5;给-3通常,int result = (-a) % b;当| -a |时给出正确的答案 > b为了在| -a |时获得正确的结果 <b我们应该包裹除数。int result = ((-a) % b) + b;为负a或int result = (((-a) % b) + b) % b;为正a或负a。
奥兹·埃德里

1
您的评论还不清楚。本节定义了正确的结果,示例符合该定义。对于您的示例(-3) % 5,根据定义的正确结果是-3,并且Java的正确实现应产生该结果。
starblue 2015年

我想我没有正确解释自己。当| -a | <b时,我所说的“正确答案”是为了获得肯定的结果,我们应该通过将b加到a%b中来“包装”给定的结果。在我的示例中,(-3)%5确实给出-3,并且如果我们想要正余数,则应在其上加上5,然后结果将是2
Oz Edri

6

您可以使用

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

3
@ruslik你也可以这样做:((x % k) + k) % k。(尽管您可能更
容易理解

2
@JohnKurlak您的版本是这样的:4%3 = 1或4%-3 = -2或-4%3 = 2或-4%-3 = -1,但来自ruslik的那个是这样的:4%3 = 1 OR 4%-3 = 1 OR -4%3 = -4 OR -4%-3 = 2
Joschua

1
@Joschua感谢您指出这一点。当您希望模量结果在[0, sign(divisor) * divisor)而不是的范围内时,我的代码很有帮助[0, sign(dividend) * divisor)
John Kurlak

3

您的答案在维基百科中: 模运算

它说,在Java中,模运算的符号与除数的符号相同。并且由于我们在谈论其余的除法运算就很好了,因此在您的情况下,由于-13/64 = 0,它会返回-13。-13-0 = -13。

编辑:对不起,您的问题误会了...您是对的,Java应该给出-13。您能否提供更多周围的代码?


2

语言设计者定义了带有负操作数的模算术,后者可能将其留给语言实现,然后将定义推迟到CPU体系结构中。

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


1

为了克服这个问题,您可以将64负值添加(或您的模数基础是什么),直到它为正

int k = -13;
int modbase = 64;

while (k < 0) {
    k += modbase;
}

int result = k % modbase;

结果仍将在相同的等效类中。


1

x = x + m = x - m模数m
因此-13 = -13 + 64在模数64-13 = 51模数方面64
假设Z = X * d + r,如果0 < r < X然后除法,Z/X我们称为r余数。
Z % X返回的余数Z/X


1

mod函数的定义是一个数字超出除数的最大整数倍(不大于该数字)的数量。所以在你的情况下

-13 % 64

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


0

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

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



0

根据JLS的15.17.3节,“二进制数值提升后为整数的操作数的余数运算会产生结果值,使得(a / b)* b +(a%b)等于a。在特殊情况下,除数是该类型最大可能的负整数,并且除数为-1(余数为0)。”

希望能有所帮助。


-1

我不认为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);
    }
}

5
@XaverKapeller,不!许多人指出,数学上来说-13和51是正确的。在Java中,-13是预期的答案,这也是我得到的答案,所以我不知道提交者如何获得51,这是个谜。有关上下文的模式详细信息可能有助于正确回答此问题。
Fabyen 2014年

@Xaver Kapeller:51和-13怎么都正确?Java将仅返回一个值..
ceprateek

@XaverKapeller如何记录Java实际可能是错误的答案?
罗恩侯爵

@EJP我想3年前,当我写这篇文章时,我愚蠢到足以重视数学准确性,而不是java如何处理这一事实的简单现实。感谢您提醒我删除愚蠢的评论:D
Xaver Kapeller '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.