Java BigInteger无符号左移或右移
我在int中使用BigInteger重新实现一个函数Java BigInteger无符号左移或右移,java,biginteger,bit-shift,Java,Biginteger,Bit Shift,我在int中使用BigInteger重新实现一个函数 h = n >>> log2n-- 但我在这里面临着麻烦。在原始代码中,h,n,log2n都是int类型,如果我将h,n,log2n设置为BigInteger,那么上面代码的等价表达式是什么?如何在BigInteger中执行无符号右移(>>>)? 编辑: 代码块是: int log2n = 31 - Integer.numberOfLeadingZeros(n); int h = 0, shift = 0, hi
h = n >>> log2n--
但我在这里面临着麻烦。在原始代码中,h,n,log2n都是int类型,如果我将h,n,log2n设置为BigInteger,那么上面代码的等价表达式是什么?如何在BigInteger中执行无符号右移(>>>)?
编辑: 代码块是:
int log2n = 31 - Integer.numberOfLeadingZeros(n);
int h = 0, shift = 0, high = 1;
while (h != n)
{
shift += h;
h = n >>> log2n--;
int len = high;
high = (h & 1) == 1 ? h : h - 1;
len = (high - len) / 2;
if (len > 0)
{
p = p.multiply(product(len));
r = r.multiply(p);
}
}
BigInteger类具有以下操作
BigInteger shiftLeft(int n)
BigInteger shiftRight(int n)
引用Java文档: 无符号右移运算符 (>>>)被省略,因为此操作 与之相结合没有什么意义 “无限字号”抽象 由该类提供 -1的32位整数表示形式为(二进制) 如果在这个问题上使用带符号的右移运算符(
>
),您将得到
11111111 11111111 11111111 11111111
01111111 11111111 11111111 11111111.
i、 同样的事情。如果在这个问题上使用无符号右移运算符,按1移位,您将得到
11111111 11111111 11111111 11111111
01111111 11111111 11111111 11111111.
但是BigInteger的长度是无限的。-1在大整数中的表示在理论上是正确的
11111111 111... infinite 1s here..... 11111111
无符号右移运算符意味着您将0放在最左边的点,即无穷远处。由于这没有什么意义,因此省略了运算符
至于您的实际代码,您现在需要做什么取决于周围的代码正在做什么,以及为什么为原始代码选择了无符号移位。差不多
n.negate().shiftRight(log2n)
可能有效,但这取决于具体情况。我终于找到了一个解决方案,虽然很糟糕,但它确实有效:
public BigInteger srl(BigInteger l, int width, int shiftBy) {
if (l.signum() >= 0)
return l.shiftRight(shiftBy);
BigInteger opener = BigInteger.ONE.shiftLeft(width + 1);
BigInteger opened = l.subtract(opener);
BigInteger mask = opener.subtract(BigInteger.ONE).shiftRight(shiftBy + 1);
BigInteger res = opened.shiftRight(shiftBy).and(mask);
return res;
}
整数为正的情况很简单,因为shiftRight无论如何都会返回正确的结果。但对于负数,这会变得棘手。前面提到的否定版本在BigInteger中不能像-1那样工作。否定的是1。移动它,你就得到了0。但是您需要知道BigInteger的宽度是多少。然后,通过减去一个开瓶器,基本上强制BigInteger至少具有宽度+1位。然后执行移位,并屏蔽掉引入的额外位。你用什么开瓶器并不重要,只要它不改变低位
开启器的工作原理:
BigInteger实现只存储负数的最高0位置。A-3表示为:
1111_1111_1111_1111_1101
但是只存储了一些位,我将其他的标记为X
XXXX_XXXX_XXXX_XXXX_XX01
向右移动没有任何作用,因为总是有1从左边来。所以我们的想法是减去1,在你感兴趣的宽度之外生成一个0。假设您关心最低的12位:
XXXX_XXXX_XXXX_XXXX_XX01
- 0001_0000_0000_0000
========================
XXXX_XXX0_1111_1111_1101
这迫使产生了真正的1。然后右移5
XXXX_XXX0_1111_1111_1101
>>5 XXXX_XXX0_1111_111
然后掩盖它:
XXXX_XXX0_1111_111
0000_0000_1111_111
并由此获得正确的结果:
0000_0000_1111_111
因此,零的引入迫使BigInteger实现将存储的0位置更新为比您感兴趣的位置更宽的宽度,并强制创建存储的1。您知道Java没有运算符重载,对吧?是的。我不是说运算符重载。没有找到无符号移位运算的方法或算法吗?@Tapas:没有,请查看
BigInteger
类的Javadocs。仅供参考两年前提出了这个问题,答案是肯定的。我仍然不明白为什么要从l中减去一些2^(宽度+1)。仅仅移动并掩盖新的比特是不够的吗?我添加了一些解释,这对你有帮助吗?这并不能回答问题