我有这种方法:
private static int generateNo(int randomNo, int value){
return ((randomNo*value)%256);
}
在我的例子中 randomNo = 17719 qValue = 197920
当我用计算器计算时,返回值应该为224,但是,当我运行程序时,它返回-32。
任何人都可以解释一下。
答案 0 :(得分:2)
一些提示。如果您在将数字相乘(或相加)时遇到意外的负值,则主要是数字溢出:
private static int generateNo(int randomNo, int value) {
return (int)(((long)randomNo * value) % 256);
}
答案 1 :(得分:2)
Java习惯于使用有符号余数而不是通常指模数(欧几里得除法的非负余数)的运算。幸运的是,对于2的幂,有一个非常简单的解决方法:使用按位&
。无论如何,这比较容易想到,因为它是对位的微不足道的操作,而不是复杂的除法算法的结果。
例如:
private static int generateNo(int randomNo, int value) {
return randomNo * value & 255;
}
由于& 255
保证只能设置结果的低8位,因此结果不可能为负。因此,结果肯定在[0..255]范围内。
如果您想要结果的一些低位(例如最低的8位),请先保留乘法换行。如果您想计算(x * y) MOD p
不是2的幂的情况下,它将无法正常工作,因为这样(在解决Java的带符号余数之后),实际的计算就变成了(由于包装){{ 1}}。 IFF p
除以2³²(即,如果((x * y) MOD 2³²) MOD p
是不超过2³²的2的幂)然后可简化为p
。
或者具有更高的位级别视图:乘积的位是“全”乘积的最低32位(两个32位整数的全积具有64位),当然,如果我们只需要这些位(或其中的一些子集,例如最低的8个),就可以了。但是,如果我们想要的结果取决于乘积的32个高位,那么显然我们将需要计算这些位。 p
的{{1}}不是2的幂将取决于整个乘积的所有位。
答案 2 :(得分:1)
17719*197920 = 3506944480
,它比Integer.MAX_VALUE
大。
这样,乘法会使int的范围溢出,结果为-788022816
。
因此,取模数会得出负结果。
答案 3 :(得分:1)
这里有两件事在玩。
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;
}