【问题标题】:Why is a Java BitSet packed in 6 bytes?为什么 Java BitSet 被打包成 6 个字节?
【发布时间】:2020-05-15 08:21:13
【问题描述】:

我正在调查BitSet,但我不清楚以下内容:

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

【问题讨论】:

    标签: java performance byte bitset


    【解决方案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 方法可以告诉我们一个 bit 的单词索引,所以如果我们给它最后一位的索引,nbits - 1(同样因为索引是从零开始的),它会给我们想要的。这应该回答你的第二个问题。

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

    【讨论】:

      【解决方案2】:

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

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

          /*
           * 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 的 BitSet。那么你需要一个大小为 0 的数组。
      • 假设您要初始化一个最初包含 1 到 64 个条目的 BitSet。那么你需要一个大小为 1 的数组。
      • 假设您要初始化一个最初包含 65 到 128 个条目的 BitSet。那么你需要一个大小为 2 的数组。

      等等。

      这意味着,您将原始范围 (1-64, 65-128) 映射到“减一” (0-63, 64-127),除以 64 (0, 1) 并再次增加结果 (1 , 2) 获取数组中需要的单词数。


      为了证明两者:

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

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

      (128-1)/64 + 1 = 127/64 + 1 = 1 + 1 = 2。(请记住,整数除法趋向于较小的值。)

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

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

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

      好吧,在这种情况下,您在数组中执行的每一步都减去 64。因此,您转到索引 1 处的单词,对于“补偿”,您从 66 转到 2。

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

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

      所以

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

      【讨论】:

      猜你喜欢
      • 2015-07-02
      • 2012-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 2021-09-11
      • 1970-01-01
      相关资源
      最近更新 更多