2009-11-18 86 views
6

我一直在尋找與lucene.NET多面搜索,我發現了一個輝煌的例子here這解釋了一個相當數量,除了它完全忽略了檢查位數組中的項目的基數的函數的事實。有人可以向我解釋這個GetCardinality方法在做什麼?

任何人都可以給我一個它正在做的事情嗎?我不明白的主要原因是bitsSetArray是爲什麼創建的,它用於什麼以及if語句如何在for循環中工作。

這可能是一個很大的問題,但我必須明白這是如何工作的,我甚至可以考慮在我自己的代碼中使用它。

由於

public static int GetCardinality(BitArray bitArray) 
    { 
     var _bitsSetArray256 = new byte[] {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; 
     var array = (uint[])bitArray.GetType().GetField("m_array", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(bitArray); 
     int count = 0; 

     for (int index = 0; index < array.Length; index ++) 
      count += _bitsSetArray256[array[index] & 0xFF] + _bitsSetArray256[(array[index] >> 8) & 0xFF] + _bitsSetArray256[(array[index] >> 16) & 0xFF] + _bitsSetArray256[(array[index] >> 24) & 0xFF]; 

     return count; 
    } 

回答

11

_bitsSetArray256陣列與值進行初始化,使得_bitsSetArray256[n]包含的n二進制表示設定的比特數,對於0..255n

例如,_bitsSetArray256[13]等於3,因爲二進制中的13是1101其中包含3 1 s。

這樣做的原因是,預先計算這些值並存儲它們要快得多,而不是每次(或按需)處理它們。這不是像在1中的數字一樣,二進制表示中的13會永遠改變,畢竟:)

for循環中,我們循環了一個uint的數組。 C#uint是一個32位數量,即由4個字節組成。我們的查找表告訴我們在一個字節中設置了多少位,所以我們必須處理四個字節中的每一個。 count +=行中的位操作將提取四個字節中的每一個字節,然後從查找數組中獲取其位數。將所有四個字節的位數加在一起給出uint的位數作爲一個整體。

因此,如果給定BitArray,該函數挖掘到uint[] m_array成員,然後返回在其中uint s的二進制表示中設置的總位數。

+0

輝煌,感謝AakashM。其中一些仍然在我的頭上,但至少我理解該方法的概念以及它正在做什麼。 –

5

我只是想發佈一篇關於bitArrays的文章,對於那些正在開發我們自己版本的Lucene.net版本的人來說。請參閱:http://dotnetperls.com/precomputed-bitcount

這是一個很好的解決方法來獲取整數(這是上述代碼示例的一大部分)中的位的基數的方式。

在我的多面搜索和其他一些簡單的更改中,我在文章中忽略了該方法,因此我可以減少花費大約65%的時間。 其中的差異:

  1. 聲明的_bitcount全球(所以它不是每次調用創建)
  2. 更改爲到的foreach(ANT探查顯示,這裏25%的漲幅)
  3. Implementening 65535臺與256位一次移位16位而不是8位。

    private static int[] _bitcounts = InitializeBitcounts(); 
    
    private static int GetCardinality(BitArray bitArray) 
    { 
        uint[] array = (uint[])bitArray.GetType().GetField("m_array", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(bitArray); 
    
        int count = 0; 
        foreach (uint value in array) 
        { 
         count += _bitcounts[value & 65535] + _bitcounts[(value >> 16) & 65535];   
        } 
        return count; 
    } 
    
    private static int[] InitializeBitcounts() 
    { 
        int[] bitcounts = new int[65536]; 
        int position1 = -1; 
        int position2 = -1; 
        // 
        // Loop through all the elements and assign them. 
        // 
        for (int i = 1; i < 65536; i++, position1++) 
        { 
         // 
         // Adjust the positions we read from. 
         // 
         if (position1 == position2) 
         { 
          position1 = 0; 
          position2 = i; 
         } 
         bitcounts[i] = bitcounts[position1] + 1; 
        } 
        return bitcounts; 
    } 
    
相關問題