了解Integer.highestOneBit()方法实现背后的逻辑

时间:2018-11-19 06:39:49

标签: java bit

Java Integer类具有静态方法highestOneBit方法,该方法将在指定值的最高一位的位置返回一个单个一位的值;如果指定值本身等于,则返回零零。

例如int 17的输入将返回16;由于17可以二进制表示为10001,所以它将返回最远的一位,等于16。

在Integer类中,它在Java文档中具有以下实现。

    public static int highestOneBit(int i) {
    // HD, Figure 3-1
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >> 16);
    return i - (i >>> 1);
}

我只想知道以这种方式实现它的逻辑以及使用移位操作的逻辑 。谁能给它一点点光。

3 个答案:

答案 0 :(得分:4)

此算法为给定的i计算其二进制表示形式:

0..01XXXXXXX...XXXX

0..011111111...1111

这就是5个|=运算符的作用。

然后,在return语句中,它从中减去右移一位的值

0..001111111...1111

获得结果

0..010000000...0000

它如何工作:

第32位(最左侧)可能的最高1位。假设输入数字在该位中有1:

1XXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX

您或该值右移1 (i >> 1)并得到

11XXXXXX XXXXXXXX XXXXXXXX XXXXXXXX

然后将您或该新值右移2 (i >> 2)并得到

1111XXXX XXXXXXXX XXXXXXXX XXXXXXXX

然后将您或该新值右移4 (i >> 4)并得到

11111111 XXXXXXXX XXXXXXXX XXXXXXXX

然后将您或该新值右移8 (i >> 8)并得到

11111111 11111111 XXXXXXXX XXXXXXXX

最后,您或该新值的值向右移16 (i >> 16)并得到

11111111 11111111 11111111 11111111

如果最高的1位小于第32位,则这些操作仍会将其右边的所有位都变为1,并使其余(较高的位)保持为0。

答案 1 :(得分:1)

i |=语句有助于计算与i相同长度的序列。例如,对于101011,它计算111111。我已经说明了它在this answer中的工作方式(由于我在移动设备上,因此目前无法重新输入)。

因此,基本上,一旦有了一串字符串,将其自身右移一位就可以得出H.O。位。

111111 - (111111 >>> 1) = 111111 - 011111 = 100000

答案 2 :(得分:1)

前五行(i |= (i >> x))会将最高1位以下的每一位都设置为1。然后,最后一行将减去最高1位以下的每1位,因此只有最高1位会保留下来。

为简单起见,我们假设int为8位。在这种情况下,代码将如下所示:

public static int highestOneBit(int i) {
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    return i - (i >>> 1);
}

现在,假设我们的值为128(10000000)。这将发生:

// i == 10000000
i |= (i >>  1); // i = 10000000 | 11000000 = 11000000 
i |= (i >>  2); // i = 11000000 | 11110000 = 11110000 
i |= (i >>  4); // i = 11110000 | 11111111 = 11111111
return i - (i >>> 1); // 11111111 - 01111111 = 10000000

>>是算术右移,因此它将保留带符号的位。 最后的>>>是逻辑右移,它将不保留带符号的位。它将始终在左侧插入零。

现在,让我们尝试64(01000000):

// i == 01000000
i |= (i >>  1); // i = 01000000 | 00100000 = 01100000 
i |= (i >>  2); // i = 01100000 | 00011000 = 01111000 
i |= (i >>  4); // i = 01111000 | 00000111 = 01111111
return i - (i >>> 1); // 01111111 - 00111111 = 01000000