Java MOD 运算符 returns 负值
Java MOD operator returns negative value
我有这个方法:
private static int generateNo(int randomNo, int value){
return ((randomNo*value)%256);
}
在我的例子中
随机数 = 17719
qValue = 197920
当我用计算器计算时,返回值应该是 224,然而,当我 运行 程序时,它 returns -32.
谁能解释一下。
17719*197920 = 3506944480
,大于Integer.MAX_VALUE
.
这样,乘法溢出了int的范围,结果是-788022816
。
因此,取模会导致负结果。
一点提示。如果在乘法(或求和)数字时出现意外的负值,这主要是数字溢出:
private static int generateNo(int randomNo, int value) {
return (int)(((long)randomNo * value) % 256);
}
这里有两件事在起作用。
- 将两个
int
相乘可以得到大于 Integer.MAX_VALUE
(2147483647) 的数字,它回绕为负数。
- 对正数和负数应用取模运算符得到负数。
您需要考虑您希望此函数如何在给定边缘情况值(例如非常大的整数或负数)的情况下工作。
例如generateNo(-100, 50)
应该生产什么?
您可能希望在执行模数之前确保您的值是正数,如下所示:
Math.abs(randomNo * value) % 256
然而,这实际上有一个非常有趣的边缘情况,其中 Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
因为它溢出了。
相反,在 结果上使用 Math.abs
:
Math.abs((randomNo * value) % 256)
我还将提供一些关于此功能的一般性评论。这些名称并不能真正解释它的作用。为什么 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 属于使用 有符号余数 的阵营,而不是通常表示模数(欧几里德除法的非负余数)的运算。幸运的是,对于 2 的幂,有一个非常简单的解决方法:使用按位 &
。无论如何,这更容易考虑,因为它是对位的微不足道的操作,而不是复杂除法算法的结果。
例如:
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³²(即当且仅当 p
是不超过 2³² 的二的幂)then 简化为 (x * y) MOD p
.
或者更比特级的观点:乘积的比特是"full"乘积的最低32位(两个32位整数的完整乘积有64位),当然如果我们只需要这些位(或它们的某些子集,例如最低的 8 位)就可以了。但如果我们想要的结果取决于乘积的 32 位高位,那么显然我们需要计算这些位。 (x * y) MOD p
其中 p
不是 2 的幂将取决于完整产品的所有位。
我有这个方法:
private static int generateNo(int randomNo, int value){
return ((randomNo*value)%256);
}
在我的例子中 随机数 = 17719 qValue = 197920
当我用计算器计算时,返回值应该是 224,然而,当我 运行 程序时,它 returns -32.
谁能解释一下。
17719*197920 = 3506944480
,大于Integer.MAX_VALUE
.
这样,乘法溢出了int的范围,结果是-788022816
。
因此,取模会导致负结果。
一点提示。如果在乘法(或求和)数字时出现意外的负值,这主要是数字溢出:
private static int generateNo(int randomNo, int value) {
return (int)(((long)randomNo * value) % 256);
}
这里有两件事在起作用。
- 将两个
int
相乘可以得到大于Integer.MAX_VALUE
(2147483647) 的数字,它回绕为负数。 - 对正数和负数应用取模运算符得到负数。
您需要考虑您希望此函数如何在给定边缘情况值(例如非常大的整数或负数)的情况下工作。
例如generateNo(-100, 50)
应该生产什么?
您可能希望在执行模数之前确保您的值是正数,如下所示:
Math.abs(randomNo * value) % 256
然而,这实际上有一个非常有趣的边缘情况,其中 Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
因为它溢出了。
相反,在 结果上使用 Math.abs
:
Math.abs((randomNo * value) % 256)
我还将提供一些关于此功能的一般性评论。这些名称并不能真正解释它的作用。为什么 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 属于使用 有符号余数 的阵营,而不是通常表示模数(欧几里德除法的非负余数)的运算。幸运的是,对于 2 的幂,有一个非常简单的解决方法:使用按位 &
。无论如何,这更容易考虑,因为它是对位的微不足道的操作,而不是复杂除法算法的结果。
例如:
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³²(即当且仅当 p
是不超过 2³² 的二的幂)then 简化为 (x * y) MOD p
.
或者更比特级的观点:乘积的比特是"full"乘积的最低32位(两个32位整数的完整乘积有64位),当然如果我们只需要这些位(或它们的某些子集,例如最低的 8 位)就可以了。但如果我们想要的结果取决于乘积的 32 位高位,那么显然我们需要计算这些位。 (x * y) MOD p
其中 p
不是 2 的幂将取决于完整产品的所有位。