Java位移位的奇怪之处

发布于 2024-08-19 23:19:23 字数 819 浏览 4 评论 0原文

Java 有 2 个用于右移的位移运算符:

>> shifts right, and is dependant on the sign bit for the sign of the result

>>> shifts right and shifts a zero into leftmost bits

http://java .sun.com/docs/books/tutorial/java/nutsandbolts/op3.html

这看起来相当简单,所以任何人都可以向我解释为什么这段代码在给 bar 赋予 -128 的值时会产生一个值foo 的 -2:

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

这意味着获取一个 8 位字节,最左边 2 位的掩码,并将它们移到最右边的 2 位。 Ie:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010

结果实际上是-2,也就是

0b11111110

Ie。 1 而不是零被移到左侧位置

Java has 2 bitshift operators for right shifts:

>> shifts right, and is dependant on the sign bit for the sign of the result

>>> shifts right and shifts a zero into leftmost bits

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/op3.html

This seems fairly simple, so can anyone explain to me why this code, when given a value of -128 for bar, produces a value of -2 for foo:

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

What this is meant to do is take an 8bit byte, mask of the leftmost 2 bits, and shift them into the rightmost 2 bits. Ie:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010

The result actually is -2, which is

0b11111110

Ie. 1s rather than zeros are shifted into left positions

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

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

发布评论

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

评论(3

棒棒糖 2024-08-26 23:19:23

这是因为 &实际上正在执行到 int 的提升 - 这留下了大量的“1”位。然后右移,将最左边的 2 位保留为 0,然后通过转换回字节来忽略这些最左边的位。

当您分离出操作时,这一点会变得更清楚:

public class Test
{
    public static void main(String[] args)
    {
        byte bar = -128;
        int tmp = (bar & ((byte)-64)) >>> 6;
        byte foo = (byte)tmp;
        System.out.println(tmp);
        System.out.println(foo);
    }
}

打印

67108862
-2

So 再次进行位算术:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2

即使您从 & 中得到了正确的结果;操作(通过在该点进行转换),>>> 无论如何都会首先将第一个操作数提升为 int

编辑:解决方案是改变掩盖事物的方式。不要用 -64 进行掩码,而只需用 128+64=192=0xc0 进行掩码:

byte foo = (byte)((bar & 0xc0) >>> 6);

这样,您实际上就只留下您想要的两位,而不是在最高有效 24 位中加载 1。

It's because the & is actually performing promotion to int - which leaves an awful lot of "1" bits. You're then shifting right, leaving the leftmost 2 bits as 0, but then ignoring those leftmost bits by casting back to byte.

This becomes clearer when you separate out the operations:

public class Test
{
    public static void main(String[] args)
    {
        byte bar = -128;
        int tmp = (bar & ((byte)-64)) >>> 6;
        byte foo = (byte)tmp;
        System.out.println(tmp);
        System.out.println(foo);
    }
}

prints

67108862
-2

So to do your bit arithmetic again:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2

Even if you get the right result out of the & operation (by casting at that point), >>> will promote the first operand to int first anyway.

EDIT: The solution is to change how you mask things. Instead of masking by -64, mask by just 128+64=192=0xc0 instead:

byte foo = (byte)((bar & 0xc0) >>> 6);

That way you really only get left with the two bits you want, instead of having a load of 1s in the most significant 24 bits.

我很坚强 2024-08-26 23:19:23

AFAIK,在 Java 中,大多数运算符(+、-、>>、& 等)无法处理小于 int 的任何值。因此,您的按位移位和 & 会在后台将值隐式转换为 int ,然后通过外部显式转换返回 byte 。最后一次转换消除了高位中的零。

要获得您期望的结果,请尝试在 int 上执行此操作。

AFAIK, in Java most operators (+,-,>>,& etc.) can't work on anything smaller than ints. So, your bitwise shifts and & are implicitly casting the values into int in the background and then back into byte by your explicit cast outside. The last cast gets rid of the zeroes in the higher bits.

To get results you would expect, try doing this on ints.

羅雙樹 2024-08-26 23:19:23

其他人已经告诉你原因,但我将进一步分解并提供真正问题的答案。

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

自从 &运算符会将所有内容提升为 int,其作用本质上是:

byte foo = (byte)(((int)bar & (int)((byte)-64)) >>> 6);

如果 bar 为 -128,则 (int)bar 为 0xFFFFFF80,然后与 0xFFFFFFFC0 进行 & 运算...即:0xFFFFFF80,然后将其向右移动 6 个位置get: 0x3FFFFFFE

正确的答案非常简单:

byte foo = (byte)((bar & 0xC0) >> 6);

将 bar 提升为 int 来表示 &操作,因此该 int 中剩下的唯一内容将是原始字节的前两位。然后将其右移 6 位并将其转换回字节。

Others have told you why but I'll break it down further and provide an answer to the real problem, too.

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

Since the & operator will promote everything to int, what this does is essentially:

byte foo = (byte)(((int)bar & (int)((byte)-64)) >>> 6);

If bar is -128 then (int)bar is 0xFFFFFF80 which is then &'ed with 0xFFFFFFC0... which is: 0xFFFFFF80, you then shift that right 6 places to get: 0x3FFFFFFE

The right answer is really simple:

byte foo = (byte)((bar & 0xC0) >> 6);

bar is promoted to an int for the & operation so the only thing left in that int will be the top two bits of the original byte. Then shift it right 6 bits and convert it back to bytes.

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