为什么Java的面具与0x1F的转向操作数? [英] Why does Java mask shift operands with 0x1F?

查看:390
本文介绍了为什么Java的面具与0x1F的转向操作数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java的:

 (0xFFFFFFFF的<< 1)= 0xFFFFFFFE = 0b1111111111111110
                :::
(0xFFFFFFFF的&所述;小于30)= 0xE0000000 = 0b1110000000000000
(0xFFFFFFFF的&所述;小于30)= 0xC0000000的= 0b1100000000000000
(0xFFFFFFFF的<< 31)= 0x80000000的= 0b1000000000000000

不过:<​​/ P>

 (0xFFFFFFFF的&LT;&LT; 32)= 0xFFFFFFFF的= 0b1111111111111111

逻辑上,这是没有意义的,但我相信是发生在Java的执行类似的操作:

A&LT;&LT; (二%Integer.SIZE) A&LT;&LT; (B&安培; 0x1F的)

这适用于&GT;&GT; &GT;&GT;&GT; ,太。

由> = 32显然移(以整数的情况下)将删除数据类型的所有数据,但有些时候,这是非常有用的。例如:

  int值= 0x3F43F466; //任意值
INT转变= 17; //任意值&GT; = 0
INT携带=价值和放大器; (-1下;≤(Integer.SIZE - 移));
如果(进大于0)
    ; // code ...

当然,这可以是固定的,但要找到这些错误可能是费时(我只花了几个小时跟踪类似一个向下)相当的时间。
所以,我的问题:有没有理由不返回逻辑值转移所有位的时候了。

更新:

我想这在C99中,使用以下内容:

 #包括LT&;&stdio.h中GT;
主要()
{
   INT I,VAL;
   对于(i = 0; I&LT; = 36;我++){
       VAL =(-1下;&下;ⅰ);
       的printf(%D:\\ t%d个\\ N,我,VAL);
   }
}

我发现,它的行为一样的Java,掩蔽 I和为0x1F ,而它给出一个恒定值,当提供在编译时的警告:

 警告:左移位数&GT;类型=宽度


解决方案

当然,也有:它的大多数处理器(具体包括x86),实现对位转移,并做你想做的是如何 - 要检查的偏移较大超过32,如果是这样,返回零 - 需要一个分支,它可以在现代的CPU昂贵。这不只是讨厌,它可以通过数量级慢下来。

在短,做你想要将显著的开销增加,预计将由高性能code快速炽烈的操作是什么。

有关参考,逻辑是不完全一样的,这是一个面具。详情请参见 JLS 15.19


  

如果左手操作数的提升的类型为int,仅右手操作数的五个最低阶位被用作移位距离。这是因为如果右手操作体进行按位逻辑与运算放大器&; (§15.22.1)与屏蔽值0x1F的(0b11111)。因此实际所用的偏移距离总是在0至31范围,包括


In Java:

(0xFFFFFFFF <<  1) = 0xFFFFFFFE = 0b1111111111111110
                :         :               :
(0xFFFFFFFF << 30) = 0xE0000000 = 0b1110000000000000
(0xFFFFFFFF << 30) = 0xC0000000 = 0b1100000000000000
(0xFFFFFFFF << 31) = 0x80000000 = 0b1000000000000000

However:

(0xFFFFFFFF << 32) = 0xFFFFFFFF = 0b1111111111111111

Logically this makes no sense, but what I believe to be happening is Java performing an operation similar to:

a << (b % Integer.SIZE) [edit, apparently:] a << (b & 0x1F)

This applies to >> and >>>, too.

Obviously shifting by >= 32 (in the case of an Integer) removes all data from the data-type, but there are times when this is useful. For example:

int value = 0x3F43F466; // any value
int shift = 17; // any value >= 0
int carry = value & (-1 << (Integer.SIZE - shift));
if (carry > 0)
    ; // code...

Of course this can be fixed, but finding these bugs can be quite time consuming (I just spent hours tracking a similar one down). So, my question: Is there reason for not returning the logical value when shifting all bits out?

UPDATE:

I tried this in C99, using the following:

#include<stdio.h>
main()
{
   int i, val;
   for (i = 0; i <=36; i++) {
       val = (-1 << i);
       printf("%d :\t%d\n", i, val);
   }
}

I found that it behaves the same as Java, masking i & 0x1F, whereas it provides a warning at compilation when given a constant value:

warning: left shift count >= width of type

解决方案

Sure, there is: it's how most processors (specifically including x86) implement bit shifting, and to do what you want -- to check if the shift is greater than 32, and if so, return zero -- requires a branch, which can be expensive on modern CPUs. It's not just "annoying," it can slow things down by orders of magnitude.

In short, doing what you want would add significant overhead to an operation that is expected to be blazing fast by high-performance code.

For reference, the logic isn't exactly the same as %, it's a mask. See JLS 15.19 for details:

If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

这篇关于为什么Java的面具与0x1F的转向操作数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆