簡體   English   中英

將64位整數中的所有其他位與32位整數進行比較

[英]Comparing every other bit in a 64 bit integer to a 32 bit integer

我當時正在考慮創建一個小跳棋求解器的想法。 首先,我將制作一個非常緊湊的棋盤格表示形式,然后繼續構建游戲樹等。

一個標准的棋盤具有8行4列功能 (棋盤只能對角移動)。 這給了我們32個職位! 每個位置需要3位信息... king位和color位...因此00 是非王黑色01 是非王紅色10王黑色11王紅色 這給了我們64個很好的數字(長整數的精確大小)。

但是,每個檢查器還需要一個額外的位... isOccupied位,因為每個檢查器位置可以為空,也可以填充上述四個狀態之一。 我決定采用64個狀態並將它們放入一個長的64位int,將32個占用狀態放入一個32位整數。

因此,現在有了一些背景知識,我就會遇到以下問題:我想輕松地說“板上有幾個紅色的跳棋?” 好吧,這還不錯...我們的64位整數保存如下數據:

king_color_king_color_king_color所以011001表示我們有紅色,黑色國王,紅色。

為了只獲取顏色信息,我們可以使用01010101 ... 01的位掩碼(十六進制為0x5555555555555555)。 這將國王位清零,而只留下顏色位。 因此,在與掩碼進行“與”運算之后的011001示例中,我們得到了010001。如果我們對位數( popcountbitcount )進行計數,我們將獲得紅色的數量...

啊,等一下! 這些顏色可能不是“使用中”。 我們必須檢查我們的32位整數,以查看給定的檢查器是否正在使用中! 假設我們有011個占用的32個整數...這意味着上面的第一個檢查器01(紅色非國王)...實際上並未被占用...它只是一個空的正方形。 如果要在此處移動另一個檢查器,則可能需要更新這2個國王色位,也可能不需要。 所以放在一起

32bit = 011
64bit = 011001

代表3個棋盤格位置...空棋盤格之前是紅色,其次是黑王,然后是紅色。 一旦在64位上執行010101掩碼操作,我們將得到:

64bitWithMask = 010001
32bit=011

天真的我們有2個紅色...但是實際上我們只有1個活動...我想要做的基本上是取64位字符串中的奇數位,然后將它們與32位字符串中的每一位相加...即

1 AND 0, 0 AND 1, 1 AND 1得到001,它表示紅色檢查器的數量。

或等效地,將64bitWithMask轉換為64bitWithMaskOddBits = 101然后簡單地與32位進行AND 64bitWithMaskOddBits = 101即可得出011 & 101 = 001

因此,從形式上講,是否有辦法采用長度為2X的位串,並僅采用奇數位將其減小為長度X? 我非常努力地避免循環,ifs等,並且僅使用邏輯(與,或,或,異或等)。

或者,當然,如果考慮到我的32位和64位字符串,還有另一種方法來獲取正確的紅色計數。 謝謝!

編輯:

我提出的問題的解決方案在下面的可接受的答案中得到了很好的解決,但是對於我的實際應用程序來說,更好的解決方案是將64位表示形式分成兩個32。這節省了我很多操作來提取所需的內容。 感謝LukeG和Tehtmi的幫助! 我很高興接觸到這種新的位操作新技術“並行”。

將每個其他位從一個數字壓縮成一個半長數字有些棘手,因為每個位需要移位不同的量。 但是,有一種聰明的方法可以實現比單獨處理每個位所需的操作更少的操作。 對於64位,它看起來像這樣(偽代碼):

x = x & 0x5555555555555555
// or for the alternate bits: x = (x >> 1) & 0x5555555555555555
x = (x | (x >>  1)) & 0x3333333333333333
x = (x | (x >>  2)) & 0x0f0f0f0f0f0f0f0f
x = (x | (x >>  4)) & 0x00ff00ff00ff00ff
x = (x | (x >>  8)) & 0x0000ffff0000ffff
x = (x | (x >> 16)) & 0x00000000ffffffff

這是一個32位數字(在初始掩碼之后)每個步驟的位所發生的情況的說明:

0a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p
00ab00cd00ef00gh00ij00kl00mn00op
0000abcd0000efgh0000ijkl0000mnop
00000000abcdefgh00000000ijklmnop
0000000000000000abcdefghijklmnop

例如,位g需要向右移動9 ,因此請看兩個二次方分量9 = 1 + 8 因此, g>> 1步和>> 8步中移動。

這種位算法有時被稱為“並行”。 您可能有興趣查看此著名清單 (它包括與這里發生的情況非常相關的交織。)

這種代碼的標准免責聲明是通常很難使用,因此除非有實際的性能問題(即使這樣,也請確保清楚代碼的含義),否則不應在嚴肅的項目中使用它。做,例如帶注釋)。 如果沒有性能問題,並且您仍想使用位操作,則循環解決方案仍然是首選,因為它更易於理解和使用。

如果不使用循環,我看不到有任何方法可以做到這一點。

編輯: tehtmi證明我做錯了。 我仍然認為,在此答案結尾處提出的“替代解決方案”是解決當前問題的更好方法,tehtmi提出了一個非常有趣的解決方案,如果您還沒有,則應該向上滾動並投票贊成。

我看到兩種解決方法。

第一個接近您要實現的目標是:

uint32_t occupied;
uint64_t data;

uint32_t occupiedWithRed;
for (auto i = 0; i < 32; ++i) {
    occupiedWithRed |= (data >> i) & occupied & (1 << i);
}

紅色位置的計數將是占用紅色的置位計數。

更簡單(可能更快)的方法是:

uint32_t occupied;
uint64_t data;

auto count = 0;
for (auto i = 0; i < 32; ++i) {
    if ((data >> (2 * i)) & (occupied > i)) ++count;
}

或者,執行完全不同的操作:如注釋中所述,如果將數據分成3個不同的32位無符號整數,則可以減輕生活負擔。 一種用於區分紅色和黑色,一種用於區分自由和被占領,以及一種用於區分國王和不國王。 這樣,您的任務將變得更加容易。 這將是一個按位運算並計算漢明權重的問題。

與其收集偶數或奇數位以與32個占用位進行比較,不如選擇另一種方式將它們分配到64位整數中,以便它們僅出現在奇數位置。 另外,我會將它們移動到另一個64位整數中的偶數位置。

然后,您可以輕松地將奇數位或偶數位占用整數與位置信息整數中的偶數或奇數位進行比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM