结构和类的C ++按位运算

时间:2015-07-13 19:31:36

标签: c++ bit-manipulation bit genetic-algorithm

我正在开发一个通用的遗传算法库,其中每个生物的染色体是其在记忆中的位表示。因此,例如,如果我想要改变一个有机体,我会随机翻转该对象的位。

首先,我尝试使用C ++标准库中的bitset类,但是,当转换回对象T时,我唯一的选择是使用to_ullong成员函数,这对于具有大于unsigned long long的大小位数的表示来说是一个问题。

然后我决定为任何对象T创建一个用于按位运算的通用库,因此我可以将这些操作直接应用到对象本身,而不是先将它们转换为bitset

所以你可以看到我想要实现的目标,这是图书馆的一个功能:

template<typename T>
void flip(T& x, size_t const i)
{
    x ^= 1 << i;
}

它在GA库中使用如下:

template<typename T>
void GeneticAlgorithm<T>::mutate(T& organism, double const rate)
{
    std::random_device rd;
    std::mt19937 mt(rd());

    std::uniform_real_distribution<double> dist(0, 1);

    for(size_t i = 0; i < m_nBits; ++i)
        if(dist(mt) <= rate)
            bit::flip(organism, i);
}

如果这样做会很好,但是现在我从VC ++ 2015 RC编译器收到此错误消息:

  

严重级代码描述项目文件行错误C2677二进制“^”:否   发现了全局运算符,其类型为“T”(或者没有可接受的类型)   转换)GeneticAlgorithm path \ geneticalgorithm \ geneticalgorithm \ BitManip.hpp 57

如果我为^更正此错误,我会为其他操作员获得更多错误。

我之前没有在代码中使用按位运算符,所以我猜这些运算符不应该与任何对象一起使用?如果是这样,我怎么能解决这个问题?

2 个答案:

答案 0 :(得分:2)

你想要达到的目标就是这样(参见Peter Schneider的评论):

template<typename T> void flip(T& x, size_t const i) {
    unsigned char* data = reinterpret_cast<unsigned char*>(&x);
    data[i/8] ^= (1 << (i%8));
}

它的作用是将数据x重新解释为一个字节数组(unsigned char),然后确定应该翻转哪个字节(i / 8),然后确定字节中的哪个位(i%8)。

注意:此外,在函数开头添加可能是安全的:

assert(i < sizeof(T)*8)

答案 1 :(得分:1)

我的印象是你还没有完全理解C ++提供的面向对象功能。 (当来自C中更加以数据为中心的编程时,这并非不典型.C ++专门设计用于以期望的速度进行转换并使其无痛。)

我的建议是将翻转操作封装在生物体中并让生物体处理它。作为一个例子(未经测试,但编译):

#include<climits>  // CHAR_BIT
#include<cstdlib>  // exit()

class string;
void log(const char *);

// inaccessible from the outside
constexpr int NUM_TRAITS = 1000;
constexpr size_t TRAIT_ARR_SZ = (NUM_TRAITS+CHAR_BIT-1)/CHAR_BIT;

class Organism
{ 

    char traits[TRAIT_ARR_SZ];
    int flips[NUM_TRAITS];

    /////////////////////////////////////////////////////////////
    public:

    Organism()  {  /* set traits and flips zero */  }

    // Consider a virtual function if you may derive 
    /** Invert the trait at index traitIndex */
    void flipTrait(int traitIndex)
    {
        if( traitIndex >= NUM_TRAITS ) { log("trait overflow"); exit(1); }

        int charInd = traitIndex / CHAR_BIT;
        int bitInd = traitIndex % CHAR_BIT;

        traits[traitIndex] ^= 1 << bitInd;
        flips[traitIndex]++;
    }

    // Organisms can do so much more!
    void display();
    void store(string &path);
    void load(string &path);
    void mutate(float traitRatio);
    Organism clone();
};