Java无符号除法无需强制转换为long?
我编写了一个解释器,要求我执行无符号整数的 32 位除法。在 Java 中,我可以这样做:
reg[a] = (int) ((reg[b] & 0xFFFFFFFFL) / (reg[c] & 0xFFFFFFFFL));
但我想避免转换为 long 并返回 int。 Java 已经为这种特殊情况提供了无符号右移运算符 >>>
,因此也许有一种聪明的方法可以以相同的方式进行无符号除法。
请注意,加法和乘法可以正常工作,因为二进制的补数可以正常工作。
Java 有没有更好的方法来做到这一点?
I have written an interpreter that requires me to perform 32-bit division of unsigned integers. In Java, I can do this as:
reg[a] = (int) ((reg[b] & 0xFFFFFFFFL) / (reg[c] & 0xFFFFFFFFL));
But I would like to avoid the conversion to long and back to 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.
Note that add and multiply work fine, since two's compliment numbers just work.
Is there a better way in Java to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 Java 8 及更高版本中,
Integer
具有对无符号int
进行操作的完整集合In Java 8 and up,
Integer
has a whole collection of operations on unsignedint
s那么,如果向下移动一位,则可以将所得的两个数字相除,然后向上移动两次(因为所得的数字将小 4 倍)。但这仅适用于偶数,因为您会丢失最低有效位。
我真的不认为这会节省你检查这种情况的时间。 (或检查小于 231 的数字)
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). 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 231)
您始终可以使用 BigInteger,它适用于任意大小的整数,但这比提升为 long 并强制转换为 int 的成本要高得多>。您的目的是提高性能(因此您需要一个“纯整数”解决方案来避免转换时间)还是提高代码的可读性/可理解性(在这种情况下 BigInteger 可能更整洁)?
You could always used
BigInteger
, which works on arbitrary sized integers, but that would be a lot more expensive than promoting tolong
and cast back asint
. 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)?其他人提到了简单且明确正确的方法,例如转换为
long
或使用Integer.divideUnsigned()
(Java SE 8+),或使用 <代码>BigInteger。实际上,
Integer.divideUnsigned()
是最清晰、最高效的方法,因为 JVM 可能将此函数调用内化为本机无符号除法机器指令,从而使得它的运行速度与语言级有符号除法运算符/
一样快。但为了完整起见,以下是如何以相对有效的方式在纯 Java(无 C 或汇编)中模拟
uint32 / uint32
,不使用更广泛的类型,如 < code>long 或BigInteger
:我已经在整个
int
值范围内对数百万个随机测试用例检查了此代码。如果有人想知道如何调整代码以使用long
,通过遵循逻辑中的隐式模式很容易做到这一点。Other people have mentioned simple and clearly correct approaches like casting to
long
, or usingInteger.divideUnsigned()
(Java SE 8+), or usingBigInteger
.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 likelong
orBigInteger
:I have checked this code on millions of random test cases over the full range of
int
values. In case anyone is wondering about adapting the code to work withlong
, it is easy to do so by following the implicit patterns in the logic.