当前位置: 首页 > 知识库问答 >
问题:

生成具有偶数汉明权重(popcount)c的整数

谯翔
2023-03-14

我想有效地(通过使用位黑客)生成一个给定的数k以上的所有整数,使它们具有均匀的汉明重量,而不用显式地计算它们的汉明重量。对我来说,这是升序还是降序并不重要。

一个好处(相关任务)是,如果我能生成所有具有均匀汉明权重的整数,这些整数是k的子集(在格雷码意义上)。

示例:输入-

输出全部-

输出子集-

使用popcount的示例代码:

for (unsigned int sub=1; sub<k; sub++){
  if (__builtin_popcount(sub) % 2 == 0){
    cout << sub << endl;
  }
}

对子集使用popcount的示例代码:

for (unsigned int sub=((k-1)&k); sub!=0; sub=((sub-1)&k)){
  if (__builtin_popcount(sub) % 2 == 0){
    cout << sub << endl;
  }
}

共有1个答案

宰父飞白
2023-03-14

我们可以用节点中的数字构建一个树,每个节点有两个子节点,一个具有翻转的位数x,另一个具有未翻转的位数x。我们需要排除值大于初始值的所有子节点。我们可以将popcount存储在一个变量中,并根据翻转的位值在每次翻转位时递减和递增,从而避免每次变量改变时计算popcount。< br >我不知道这种方法是否更快。我猜它可能更快,但递归函数的开销可能太大。那很有趣:

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
#include <cinttypes>
#include <cassert>
#include <bitset>
#include <cstring>

namespace gen {

bool isEven(unsigned int x) {
    return x % 2 == 0;
}

// find last set bit, just like ffs, but backwards
unsigned int fls(unsigned int x)
{
    assert(x >= 1);
    if (x == 0) {
        return 0;
    }
#ifdef __GNUC__
    const unsigned int clz = __builtin_clz(x);
#else
    #error find clz function in C++
#endif
    assert(clz >= 1 && (sizeof(x) * CHAR_BIT) >= clz + 1);
    return (sizeof(x) * CHAR_BIT) - clz - 1;
}

unsigned int popcount(unsigned int x) {
#ifdef __GNUC__
    return __builtin_popcount(x);
#else
    return std::bitset<sizeof(x)*CHAR_BIT>(x).count();
#endif
}

/**
 * Generates all integers up a given number k with even hamming weight
 * @param out - output vector with push_backed results
 * @param greycodesubset - set to true, if only interested in grey subset integers only
 * @param startk - starting k value
 * @param k - the current number value
 * @param pos - one plus the position of the bit in number k that we will change in this run
 * @param popcount - Hamming weight of number k up to position pos
 * @param changes - the number of bits changed in number k since startk. Used only if greycodesubset = true
 */
void loop(std::vector<unsigned int>& out, const bool& greycodesubset, 
    const unsigned int& startk,
    unsigned int k, unsigned int pos, unsigned int popcount,
    unsigned int changes)
{
    // k > startk may happen for example for 0b10, if we flip last byte, then k = 0b11
    if (startk < k) {
        return;
    }
    // end of recusive function
    if (pos == 0) {
        if (isEven(popcount) && k != 0) {
            out.push_back(k);
        }
        return;
    }
    // decrement pos
    --pos;

    const int mask = 1 << pos;
    const bool is_pos_bit_set = k & mask;

    // call without changes
    loop(out, greycodesubset, startk, 
        k, pos, popcount + (is_pos_bit_set ? +1 : 0), changes);
    // when finding grey code subset only we can change maximum 1 byte
    if (greycodesubset) {
        if (changes >= 1) {
            return;
        }
        ++changes;
    }
    // call with toggled bit number pos
    loop(out, greycodesubset, startk, 
        k ^ mask, pos, popcount + (!is_pos_bit_set ? +1 : 0), changes);
}

std::vector<unsigned int> run(const unsigned int& k, const bool& greycodesubsetonly)
{
    assert(k > 0);
    std::vector<unsigned int> out;
    if (k < 2) return out;

    loop(out, greycodesubsetonly, k, k, fls(k) + 1, 0, 0);

    return out;
}

} // namespace gen

int main()
{
    const unsigned int k = 14;
    const int bits_in_k = 4;

    std::vector<unsigned int> out = gen::run(k, false);
    std::vector<unsigned int> out_subset = gen::run(k, true);

    std::cout << "input-> k=" << k << "(" << std::bitset<bits_in_k>(k).to_string() << ") " << std::endl;

    std::cout << "output all-> ";
    std::for_each(out.begin(), out.end(), [](int v) {
        std::cout << v << "(" << std::bitset<bits_in_k>(v).to_string() << ") ";
    });
    std::cout << std::endl;

    std::cout << "output subsets-> ";
    std::for_each(out_subset.begin(), out_subset.end(), [](int v) {
        std::cout << v << "(" << std::bitset<bits_in_k>(v).to_string() << ") ";
    });
    std::cout << std::endl;

    return 0;
}
input-> k=14(1110)                                                                                                           
output all-> 12(1100) 10(1010) 9(1001) 6(0110) 5(0101) 3(0011)                                                               
output subsets-> 12(1100) 10(1010) 6(0110)                                                                                   
 类似资料:
  • 问题内容: 我有两个值: [3:6] 我试图在Golang中玩一些游戏,但是我找不到能够根据这些值创建数组的好方法。 我要实现的目标是: 问题答案: 您可以利用该构造使其更紧凑甚至更快: 出于好奇,可以在不使用循环变量的情况下实现循环,但是这样会更慢,并且代码也更长。通过递减: 或递增:

  • 本文向大家介绍C++生成不重复的随机整数,包括了C++生成不重复的随机整数的使用技巧和注意事项,需要的朋友参考一下 C++生成不重复的随机数,供大家参考,具体内容如下 给定正整数的范围[n,m],生成k个不重复的随机数字。 IDE是vs013。 运行结果: 这个程序可以用于班级内部按照学号进行随机抽签。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 问题来了。 给出了一个加权无向连通图G。重量是不变的。任务是提出一个算法,该算法将找到满足以下两个条件的生成树的总权重(按优先级排序): 生成树必须具有相同权重的最大边数(实际重复权重值与此无关); 总生成树权重应最小化。这意味着,例如,权重为120的生成树T1最多有4条相同权重的边(这四条边中的每一条的权重都是15)应该优于权重为140的生成树T2,这四条边最多有4条相同权重的边(这四条边中的每

  • 我想使用Math.Random生成数字1-4(整整数)。我只成功地获得了双倍或大双倍,无法弄清楚如何对最小和最大设置限制。 math.random();=0-1之间的东西作为双倍? 我见过一些人这样建议:num=math.random()*60+25;但不知道它是怎么做的,或者它是如何工作的。

  • 本文向大家介绍在C ++中计算整数中的偶数和奇数位,包括了在C ++中计算整数中的偶数和奇数位的使用技巧和注意事项,需要的朋友参考一下 给我们一个整数,任务是计算一个数字中的偶数和奇数。另外,我们将继续检查整数中的偶数是否出现偶数次,并且整数中的奇数位是否出现奇数次。 例如 说明-是的,此外,偶数出现偶数次,即2,奇数位出现奇数次,即3 说明-:否,因为偶数出现的次数是奇数,即3,而奇数出现的次数

  • 如何在每次运行程序时以随机顺序生成0,1,2,3(甚至整数),不重复? 如在,运行这个for循环:for(int x=1; x 我被要求使用math.random,但我无法解决这个问题。最接近的是: 这永远不会给我第一个数字,因为它只有1-4,我相信当它超过4时会给我一个错误。 期望的输出是四首歌曲中的每一首每次都以随机顺序打印一次。