Java MOD运算符返回负值

Java MOD运算符返回负值,java,negative-number,mod,Java,Negative Number,Mod,我有这个方法: private static int generateNo(int randomNo, int value){ return ((randomNo*value)%256); } 以我为例 随机数=17719 qValue=197920 当我用计算器计算它时,返回值应该是224,然而,当我运行程序时,它返回-32 有人能解释一下吗。17719*197920=3506944480,它大于Integer.MAX\u值 因此,乘法溢出int的范围,结果是-788022816

我有这个方法:

private static int generateNo(int randomNo, int value){
    return   ((randomNo*value)%256);
}
以我为例 随机数=17719 qValue=197920

当我用计算器计算它时,返回值应该是224,然而,当我运行程序时,它返回-32


有人能解释一下吗。

17719*197920=3506944480
,它大于
Integer.MAX\u值

因此,乘法溢出int的范围,结果是
-788022816


因此,取模结果为负值。

17719*197920=3506944480
,大于
整数.MAX_值

因此,乘法溢出int的范围,结果是
-788022816


因此,取模结果为负。

一点提示。如果在乘法(或求和)时出现意外负值,则主要是数字溢出:

private static int generateNo(int randomNo, int value) {
    return (int)(((long)randomNo * value) % 256);
}

一点提示。如果在乘法(或求和)时出现意外负值,则主要是数字溢出:

private static int generateNo(int randomNo, int value) {
    return (int)(((long)randomNo * value) % 256);
}

这里有两件事在起作用

  • 将两个
    int
    s相乘会产生一个大于
    Integer.MAX_VALUE
    (2147483647)的数字,该值会变为负数
  • 对正数和负数应用模运算符将产生负数
  • 您需要考虑在给定的边大小写值(如非常大的整数或负数)下如何使用此函数

    例如,
    generateNo(-100,50)
    应该产生什么

    在进行模数计算之前,您可能希望确保值为正值,如下所示:

    Math.abs(randomNo * value) % 256
    
    然而,这实际上有一个非常有趣的边缘情况,
    Math.abs(Integer.MIN\u VALUE)==Integer.MIN\u VALUE
    ,因为它溢出了

    相反,在结果上使用
    Math.abs

    我还将对这个函数提供一些一般性的评论。这些名字并不能真正解释它的作用。为什么
    generateNo
    ?毫无疑问,有很多方法可以生成一个数字。我建议用一个更具体的名字

    参数,
    randomNo
    value
    也有问题。为什么
    generateNo
    关心第一个参数是否是随机的

    更清楚地指定您希望发生的事情,并使用描述这些事情的名称,可能会更容易思考

    我还建议,当出现这样的问题时,分解步骤,以便了解发生了什么。比如:

    private static int generateNo(int randomNo, int value){
        final int product = randomNo * value;
        final int result = product % 256;
    
        // Breakpoint or System.out.println here, to understand the values...
        return result;
    }
    

    这里有两件事在起作用

  • 将两个
    int
    s相乘会产生一个大于
    Integer.MAX_VALUE
    (2147483647)的数字,该值会变为负数
  • 对正数和负数应用模运算符将产生负数
  • 您需要考虑在给定的边大小写值(如非常大的整数或负数)下如何使用此函数

    例如,
    generateNo(-100,50)
    应该产生什么

    在进行模数计算之前,您可能希望确保值为正值,如下所示:

    Math.abs(randomNo * value) % 256
    
    然而,这实际上有一个非常有趣的边缘情况,
    Math.abs(Integer.MIN\u VALUE)==Integer.MIN\u VALUE
    ,因为它溢出了

    相反,在结果上使用
    Math.abs

    我还将对这个函数提供一些一般性的评论。这些名字并不能真正解释它的作用。为什么
    generateNo
    ?毫无疑问,有很多方法可以生成一个数字。我建议用一个更具体的名字

    参数,
    randomNo
    value
    也有问题。为什么
    generateNo
    关心第一个参数是否是随机的

    更清楚地指定您希望发生的事情,并使用描述这些事情的名称,可能会更容易思考

    我还建议,当出现这样的问题时,分解步骤,以便了解发生了什么。比如:

    private static int generateNo(int randomNo, int value){
        final int product = randomNo * value;
        final int result = product % 256;
    
        // Breakpoint or System.out.println here, to understand the values...
        return result;
    }
    

    Java的阵营是使用带符号的余数,而不是通常意味着模(欧氏除法的非负余数)的运算。幸运的是,对于二次幂有一个非常简单的解决方法:使用位
    &
    。无论如何,这更容易考虑,因为这是一个对位的简单操作,而不是复杂除法算法的结果

    例如:

    private static int generateNo(int randomNo, int value) {
        return randomNo * value & 255;
    }
    
    这不可能有负结果,因为
    &255
    保证只能设置结果的低8位,因此结果肯定在[0..255]范围内

    如果您想要得到结果的一些较低的位,可以让乘法先换行,如这里所示(最低的8)。如果您想计算
    (x*y)MOD p
    ,其中
    p
    不是二的幂,那么它就不能正常工作,因为(在处理Java的有符号余数之后)实际计算变成(由于包装)
    ((x*y)MOD 2²)MOD p
    。IFF
    p
    除以2²(即IFF
    p
    是不超过2²的二次幂),然后简化为仅
    (x*y)模p


    或者从更比特级的角度来看:乘积的位是“完整”乘积的最低32位(两个32位整数的完整乘积有64位),当然,如果我们只需要这些位(或它们的某个子集,例如最低的8位),那么就可以了。但是如果我们想要的结果取决于乘积的32高位,那么显然我们需要计算这些位
    (x*y)MOD p
    其中
    p
    不是二的幂,将取决于整乘积的所有位。

    Java使用带符号的余数,而不是通常意味着模的运算(欧氏除法的非负余数)。幸运的是,对于二次幂有一个非常简单的解决方法:使用位
    &
    。这更容易思考