简体   繁体   English

Java 无符号除法不转换为长?

[英]Java unsigned division without casting to long?

I have written an interpreter that requires me to perform 32-bit division of unsigned integers.我编写了一个解释器,要求我对无符号整数执行 32 位除法。 In Java, I can do this as:在 Java 中,我可以这样做:

reg[a] = (int) ((reg[b] & 0xFFFFFFFFL) / (reg[c] & 0xFFFFFFFFL));

But I would like to avoid the conversion to long and back to int.但我想避免转换为 long 并返回 int。 Java already gives the unsigned right shift operator >>> for that special case, so maybe there is a clever way to do unsigned division in the same way. Java 已经为这种特殊情况提供了无符号右移运算符>>> ,所以也许有一种聪明的方法可以以同样的方式进行无符号除法。

Note that add and multiply work fine, since two's compliment numbers just work.请注意,加法和乘法可以正常工作,因为二进制的补码可以正常工作。

Is there a better way in Java to do this? Java 中有没有更好的方法来做到这一点?

Well, if you shift down by one bit, you could divide the resulting two numbers, then shift up twice (because the resulting number would be 4 times smaller).好吧,如果你向下移动一位,你可以将得到的两个数字相除,然后向上移动两次(因为得到的数字会小 4 倍)。 But that would only work on even numbers, since you would lose the least significant bit.但这仅适用于偶数,因为您会丢失最不重要的位。

I don't really think it would save you any time to check for that condition.我真的不认为这会节省您检查这种情况的任何时间。 (or check for numbers smaller then 2 31 ) (或检查小于 2 31 的数字)

在 Java 8 及更高版本中, Integer对 unsigned int s 有一个完整的操作集合

reg[a] = Integer.divideUnsigned(reg[b], reg[c]);

Other people have mentioned simple and clearly correct approaches like casting to long , or using Integer.divideUnsigned() (Java SE 8+), or using BigInteger .其他人提到了简单且明确正确的方法,例如转换为long ,或使用Integer.divideUnsigned() (Java SE 8+),或使用BigInteger

Practically speaking, Integer.divideUnsigned() is the clearest and most performant way to do it, because the JVM probably intrinsifies this function call into a native unsigned division machine instruction, making it run as fast as the language-level signed division operator / . Practically speaking, Integer.divideUnsigned() is the clearest and most performant way to do it, because the JVM probably intrinsifies this function call into a native unsigned division machine instruction, making it run as fast as the language-level signed division operator / .

But for the sake of completeness, here is how to emulate uint32 / uint32 in pure Java (no C or assembly) in a relatively efficient manner, without using wider types like long or BigInteger :但为了完整起见,这里是如何以相对有效的方式在纯 Java(没有 C 或程序集)中模拟uint32 / uint32而不使用更广泛的类型,如longBigInteger

int divideUint32(int x, int y) {
    if (y < 0) {  // i.e. 2^31 <= unsigned y < 2^32
        // Do unsigned comparison
        return (x ^ 0x8000_0000) >= (y ^ 0x8000_0000) ? 1 : 0;
    }
    else if (x >= 0 || y == 0) {
        assert y >= 0;
        return x / y;  // Straightforward or division by zero
    }
    else {  // The hard case: signed x < 0 && signed y > 0
        assert x < 0 && y > 0;
        // In other words, 2^31 <= unsigned x < 2^32 && 0 < unsigned y < 2^31
        int shift = Integer.numberOfLeadingZeros(y);
        assert shift > 0;
        assert (y << shift) < 0;
        // Do one step of long division
        if (x < (y << shift))
            shift--;
        return (1 << shift) | (x - (y << shift)) / y;
    }
}

I have checked this code on millions of random test cases over the full range of int values.我已经在整个int值范围内的数百万个随机测试用例中检查了这段代码。 In case anyone is wondering about adapting the code to work wing long , it is easy to do so by following the implicit patterns in the logic.如果有人想知道如何使代码适应long工作,那么通过遵循逻辑中的隐式模式很容易做到这一点。

You could always used BigInteger , which works on arbitrary sized integers, but that would be a lot more expensive than promoting to long and cast back as int .您始终可以使用BigInteger ,它适用于任意大小的整数,但这比提升为long并返回为int昂贵得多。 Is your intention to improve performance (hence you want a "pure integer" solution to avoid the time for casts) or to improve how readable/understandable the code is (in which case BigInteger might be neater)?您打算提高性能(因此您想要一个“纯整数”解决方案来避免转换时间)还是提高代码的可读性/可理解性(在这种情况下 BigInteger 可能更简洁)?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM