Java 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

我在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, 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)。仅仅移动并掩盖新的比特是不够的吗?我添加了一些解释,这对你有帮助吗?这并不能回答问题