为什么 Java BitSet 打包在 6 个字节中?



我正在研究BitSet,我不清楚以下内容:

  1. 当我们传递位数时,有一个除以6.为什么使用6而不是 2 的幂?
  2. 初始化底层数组时,为什么先减 1 然后除以6,然后加 1?

我假设你在问JDK中的这段代码:

private static int wordIndex(int bitIndex) {
return bitIndex >> ADDRESS_BITS_PER_WORD; // ADDRESS_BITS_PER_WORD is 6, question 1
}
public BitSet(int nbits) {
// nbits can't be negative; size 0 is OK
if (nbits < 0)
throw new NegativeArraySizeException("nbits < 0: " + nbits);
initWords(nbits);
sizeIsSticky = true;
}
private void initWords(int nbits) {
words = new long[wordIndex(nbits-1) + 1]; // question 2
}

initWords初始化一个long[]来支持位,实质上是将位存储为 64 位的"字"。请注意,这似乎是一个实现细节。这个long[]应该持续多久?好吧,它应该是最后一个单词+ 1 的单词索引,因为索引是从零开始的。

最后一个单词的索引是什么?好吧,wordIndex方法可以告诉我们一个位的单词索引,所以如果我们给它最后一个位的索引,nbits - 1(再次因为索引是从零开始的(,它会给我们想要的。这应该回答你的第二个问题。

wordIndex如何找到单词索引?好吧,long中有 64 位 ,所以我们只需要将bitIndex除以 64。除以 64 的另一种方法是什么?左移 6 次,因为 64 = 2 的 6 次方。有关更多信息,请参阅此帖子。

我想你说的是这个类的实现?

它在源文件的注释中这样说:

/*
* BitSets are packed into arrays of "words."  Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns.
*/

因此,从给定的位号来看,较低的 6 位用于寻址 64 位字中的位,其余位用于寻址字。


对于第 2 点,我想你谈论

的是
wordIndex(nbits-1) + 1

这是

bitIndex >> ADDRESS_BITS_PER_WORD
  • 假设您要初始化一个最初包含 0 个条目的位集。然后,您需要数组大小为 0。
  • 假设您要初始化最初包含 1 到 64 个条目的 BitSet。然后,您需要数组大小为 1。
  • 假设您要初始化一个最初包含 65 到 128 个条目的 BitSet。然后,您需要数组大小为 2。

等等。

这意味着,您将原始范围(1-64,65-128(映射到"少一个"(0-63,64-127(,除以64(0,1(并再次增加结果(1,2(以获得数组中所需单词的数量。


要演示两者:

假设您想要一个包含 128 个条目的位集。你初始化它,你会得到一个包含 2 个 64 位条目的数组。为什么?

这是因为 wach word 可以容纳 64 位,所以为了容纳 128 位,你需要 2 个数组条目:

(128-1(/64 + 1 = 127/64 + 1 = 1 + 1 = 2。(请记住,整数除法朝向较低的值。

现在,您要设置双 5、13 和 66。

位 5 和 13 很好 - 您只需在索引 0 处设置单词中的第 5 位和第 13 位。

但是你用 66 做什么?每个字只有64位!(0..63(

好吧,在这种情况下,您在数组中执行的每个步骤都减去 64。所以你去索引 1 的单词,对于"补偿",你从 66 到 2。

这正是这些位操作所发生的情况:从这些位索引中的每一个中,较低的 6 位被获取并用作相应字中的位地址。

5 = 0000101 = 0/5 13 = 0 001101 = 0/13 66 = 1 000001 = 1/2

所以

  • 通过在单词 0 中设置位 5 来设置 5。
  • 通过在字 0 中设置位 13 来设置 13。
  • 66 是通过在单词 2 中设置位 1 来设置的。

最新更新