Java 中的无符号模
Unsigned modulo in Java
我正在移植一些对 uint32_t 求模的 C 代码。 uint32_t 按位适合 Java int,但我不知道如何在不转换为 long 的情况下对其执行模运算。这是我现在的代码:
int i = 0xffffffff;
long asUnsigned = Integer.toUnsignedLong(i);
int mod = (int) (asUnsigned % 42L);
我可以在不转换为 long 的情况下执行此模计算吗?
@那个人的答案更适合 Java 8+。我会把它留在这里,以防它对使用旧版本 Java.
的任何人有用
转换为 long
几乎可以肯定是最好的方法。
否则需要分支;要获得负 int
值的正确结果,您需要调整 int
表示的无符号数被 232 偏移的事实,并且当您除以模数时,此偏移量通常不会有 0 的余数。如果模数是常数(在您的示例中为 42),那么您可以对偏移量进行硬编码:
static int unsignedMod42(int x) {
if(x >= 0) {
return x % 42;
} else {
// 2**32 = 4 (mod 42)
return ((x % 42) + 42 + 4) % 42;
}
}
如果模数是一个变量,那么您必须在运行时计算正确的偏移量:
static int unsignedMod(int x, int y) {
if(y <= 0 || y * y <= 0) {
throw new IllegalArgumentException("y = " + y);
} else if(x >= 0) {
return x % y;
} else {
// compute 2**32 mod y, by repeated squaring
int offset = 2;
for(int i = 0; i < 5; ++i) { offset = (offset * offset) % y; }
return ((x % y) + y + offset) % y;
}
}
请注意,因为这里的偏移量是通过重复平方计算的,所以我们不能允许乘法可能溢出的模数。大概有一种更好的方法来计算正确的偏移量——例如,通过重复乘法可以使模数达到 Integer.MAX_VALUE / 2
。
使用Integer.remainderUnsigned(int dividend, int divisor)
(javadoc):
Returns the unsigned remainder from dividing the first argument by the second where each argument and the result is interpreted as an unsigned value.
我正在移植一些对 uint32_t 求模的 C 代码。 uint32_t 按位适合 Java int,但我不知道如何在不转换为 long 的情况下对其执行模运算。这是我现在的代码:
int i = 0xffffffff;
long asUnsigned = Integer.toUnsignedLong(i);
int mod = (int) (asUnsigned % 42L);
我可以在不转换为 long 的情况下执行此模计算吗?
@那个人的答案更适合 Java 8+。我会把它留在这里,以防它对使用旧版本 Java.
的任何人有用转换为 long
几乎可以肯定是最好的方法。
否则需要分支;要获得负 int
值的正确结果,您需要调整 int
表示的无符号数被 232 偏移的事实,并且当您除以模数时,此偏移量通常不会有 0 的余数。如果模数是常数(在您的示例中为 42),那么您可以对偏移量进行硬编码:
static int unsignedMod42(int x) {
if(x >= 0) {
return x % 42;
} else {
// 2**32 = 4 (mod 42)
return ((x % 42) + 42 + 4) % 42;
}
}
如果模数是一个变量,那么您必须在运行时计算正确的偏移量:
static int unsignedMod(int x, int y) {
if(y <= 0 || y * y <= 0) {
throw new IllegalArgumentException("y = " + y);
} else if(x >= 0) {
return x % y;
} else {
// compute 2**32 mod y, by repeated squaring
int offset = 2;
for(int i = 0; i < 5; ++i) { offset = (offset * offset) % y; }
return ((x % y) + y + offset) % y;
}
}
请注意,因为这里的偏移量是通过重复平方计算的,所以我们不能允许乘法可能溢出的模数。大概有一种更好的方法来计算正确的偏移量——例如,通过重复乘法可以使模数达到 Integer.MAX_VALUE / 2
。
使用Integer.remainderUnsigned(int dividend, int divisor)
(javadoc):
Returns the unsigned remainder from dividing the first argument by the second where each argument and the result is interpreted as an unsigned value.