【问题标题】:Unsigned modulo in JavaJava中的无符号模数
【发布时间】:2021-12-06 18:05:29
【问题描述】:

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

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

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

【问题讨论】:

    标签: java bit-manipulation modulo unsigned-integer signed-integer


    【解决方案1】:

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

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

    【讨论】:

    【解决方案2】:

    @那个其他人的答案是 Java 8+ 的首选。我将把它留在这里,以防它对使用旧版本 Java 的人有用。


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

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

    【讨论】:

      猜你喜欢
      • 2011-05-25
      • 1970-01-01
      • 2014-02-01
      • 2010-10-13
      • 1970-01-01
      • 2017-11-08
      • 1970-01-01
      • 2012-06-30
      • 1970-01-01
      相关资源
      最近更新 更多