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
。IFFp
除以2²(即IFFp
是不超过2²的二次幂),然后简化为仅(x*y)模p
或者从更比特级的角度来看:乘积的位是“完整”乘积的最低32位(两个32位整数的完整乘积有64位),当然,如果我们只需要这些位(或它们的某个子集,例如最低的8位),那么就可以了。但是如果我们想要的结果取决于乘积的32高位,那么显然我们需要计算这些位(x*y)MOD p
其中p
不是二的幂,将取决于整乘积的所有位。Java使用带符号的余数,而不是通常意味着模的运算(欧氏除法的非负余数)。幸运的是,对于二次幂有一个非常简单的解决方法:使用位&
。这更容易思考