0

我正在移植一些在 uint32_t 上进行模运算的 c 代码。uint32_t 按位适合 Java int,但我无法弄清楚如何在不转换为 long 的情况下对其执行模运算。这是我现在拥有的代码:

int i = 0xffffffff;
long asUnsigned = Integer.toUnsignedLong(i);
int mod = (int) (asUnsigned % 42L);

我可以在不转换为 long 的情况下执行此模计算吗?

4

2 回答 2

4

使用Integer.remainderUnsigned(int dividend, int divisor)javadoc):

返回第一个参数除以第二个参数得到的无符号余数,其中每个参数和结果都被解释为无符号值。

于 2021-10-19T21:00:12.893 回答
2

@that other guy's answer是Java 8+的首选。我将把它留在这里,以防它对使用旧版本 Java 的人有用。


转换为 along几乎可以肯定是最好的方法。

否则,您将需要分支;要获得负值的正确结果int,您需要调整表示的无符号数int偏移 2 32的事实,并且当您除以模数时,该偏移量通常不会有余数 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

于 2021-10-19T20:47:26.170 回答