BigInteger 无符号左移或右移

发布于 2024-10-21 06:54:29 字数 651 浏览 1 评论 0原文

我正在 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);
        }
    }

I am reimplementing a function using BigInteger in place in int. Now there is step

h = n >>> log2n--

But I am facing trouble here. In original code h, n, log2n all are int type, if I set h, n, and log2n to BigInteger what will be the equivalent expression of the above code? How do I perform an unsigned right shift (>>>) in BigInteger?

Edit:
The code block is :

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);
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

巷雨优美回忆 2024-10-28 06:54:29

引用Java文档:

无符号右移运算符
(>>>) 被省略,因为此操作
结合起来没有什么意义
“无限字长”抽象
由此类提供。

-1 的 32 位整数表示为(二进制)

11111111 11111111 11111111 11111111

如果对此使用有符号右移运算符 (>>),您将得到

11111111 11111111 11111111 11111111 

相同的结果。如果您对此使用无符号右移运算符,移位 1,您将得到

01111111 11111111 11111111 11111111.

But BigInteger has an unlimited length。 BigInteger 中 -1 的表示理论上是

11111111 111... infinite 1s here..... 11111111

无符号右移运算符意味着您将 0 放在最左边的点 - 即无穷大。由于这没有什么意义,因此省略了该运算符。

至于您的实际代码,您现在需要做什么取决于周围代码正在做什么以及为什么为原始代码选择无符号移位。像这样的东西

n.negate().shiftRight(log2n)

可能有效,但这一切都取决于具体情况。

Quoting from the Java docs:

The unsigned right shift operator
(>>>) is omitted, as this operation
makes little sense in combination with
the "infinite word size" abstraction
provided by this class.

An 32-bit integer representation of -1 is (in binary)

11111111 11111111 11111111 11111111

If you use the signed right-shift operator (>>) on this, you'll get

11111111 11111111 11111111 11111111 

i.e. the same thing. If you use the unsigned right-shift operator on this, shifting by 1, you'll get

01111111 11111111 11111111 11111111.

But BigInteger has an unlimited length. The representation of -1 in a BigInteger is theoretically

11111111 111... infinite 1s here..... 11111111

The unsigned right-shift operator would imply that you were putting a 0 at the leftmost point - which is at infinity. Since this makes little sense, the operator is omitted.

As regards your actual code, what you need to do now depends on what the surrounding code is doing and why an unsigned shift was chosen for the original code. Something like

n.negate().shiftRight(log2n)

might work, but it all depends on the circumstances.

随遇而安 2024-10-28 06:54:29

我终于找到了一个解决方案,它很糟糕,但它有效:

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 至少具有 width+1 位。然后执行移位,并掩盖您引入的额外位。使用什么开启器并不重要,只要它不改变较低的位即可。

开启器的工作原理:

BigInteger 实现仅存储负数的最高 0 位置。 -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。

I finally found a solution, it's awful, but it works:

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;
}

The case that your integer is positive is trivial, as shiftRight will return the correct result anyway. But for negative numbers this gets tricky. The negate version mentioned earlier does not work as -1 in BigInteger negated is 1. Shift it and you have 0. But you need to know what the width of your BigInteger is. You then basically force the BigInteger to have at least width+1 bits by subtracting an opener. Then you perform the shifting, and mask away the extra bit that you introduced. It doesn't really matter what opener you use, as long as it doesn't alter the lower bits.

How the opener works:

The BigInteger implementation does only store the highest 0 position for negative numbers. A -3 is represented as:

1111_1111_1111_1111_1101

But only some bits are stored, I marked the others as X.

XXXX_XXXX_XXXX_XXXX_XX01

Shifting to the right does nothing as there are always 1's coming from the left. So the idea is to substract a 1 to generate a 0 outside of the width that you are interested in. Assuming you care about the lowest twelve bit:

XXXX_XXXX_XXXX_XXXX_XX01
-    0001_0000_0000_0000
========================
XXXX_XXX0_1111_1111_1101

This forced the generation of real 1s. You then shift right by lets say 5.

XXXX_XXX0_1111_1111_1101
>>5   XXXX_XXX0_1111_111

And then mask it:

XXXX_XXX0_1111_111
0000_0000_1111_111

And therewith receive the correct result:

0000_0000_1111_111

So the introduction of the zero forced the BigInteger implementation to update the stored 0 position to a width that is higher than the one you are interested in and forced the creation of stored 1s.

我为君王 2024-10-28 06:54:29

BigInteger类有以下操作

 BigInteger     shiftLeft(int n)

 BigInteger     shiftRight(int n)

The BigInteger class has the following operations

 BigInteger     shiftLeft(int n)

 BigInteger     shiftRight(int n)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文