簡體   English   中英

將設置位移動到64位整數的末尾

[英]Moving set bits to the end of 64bits integer

我正在開發一個函數,它接受一個64位整數作為參數,並返回一個64位整數,最后包含所有設置位。

01011001 -> 00001111   // examples
00010100 -> 00000011

我首先想到了以下算法:

nb_ones = countSetBit(x)
int64 res = 1
for i from 1 to nb_ones+1:
    res |= (1 << i)

這里countSetBit這里定義的

有更直接的事情嗎? 我在C ++工作

countSetBit可能已經針對您的平台進行了優化。

要在最后設置給定數量的1,只需轉到下一個2的冪並減去1。

nb_ones = countSetBit(x)
int64 res = nb_ones == 64 ? -1 : ((1 << nb_ones) - 1);

編輯:來自MSalters評論的不錯的非分支解決方案:

int64_t res = ((1^(nb_ones>>6))<<nb_ones)-1;

(如果nb_ones == 64,則nb_ones中的第6位是if-and-only-only)

<< 64的未定義行為的背景可能是相應的本機操作可能只使用最大合理移位值所需的參數位,並且在C ++端處理此操作會增加開銷。

你可以避免循環:

const auto nb_ones = countSetBit(x)
if (nb_ones == 64) {
    return -1; // 0xFFFFFFFFFFFFFFFF;
} else {
    return (1u << nb_ones) - 1;
}

計算所有位有點過分,因為大多數CPU都有針對零的有效測試。

所以,我們所做的就是使用它作為退出條件:

output = 0;
while (input != 0) {
  if (input & 1) output = (output<<1)+1;
  input >>= 1;
}

循環將輸入向右移動,每當一個位移出input時,就會output一個額外的位。 顯然,這會增加與input output位數(可能為0,可能為64)。 output中的位是連續的,因為只有在添加位時才會移位output

如果你的CPU有一個bitcount操作,那當然會更快。 如果你在x86或ARM程序集中實現它,你會使用input&1是由>>=1移出的相同位的事實。

既然你有幾個有效的答案,當你真正問一個簡單的一個,對品種的慢,但概念上,極簡單的答案:

uint64_t num(uint64_t x)
{
    // construct a base-2 string
    auto s = std::bitset<64>(x).to_string();
    // sort the 1s to the end
    std::sort(begin(s), end(s));
    // and convert it back to an integer
    return std::bitset<64>(s).to_ulong();
}

我想你只需一個循環即可完成:

std::uint64_t bits_to_end(std::uint64_t n)
{
    std::uint64_t x = 0;

    for(std::uint64_t bit = 0, pos = 0; bit < 64; ++bit)
        if(n & (1ULL << bit))
            x |= (1ULL << pos++);

    return x;
}

暫無
暫無

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

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