我正在开发一个通用的遗传算法库,其中每个生物的染色体是其在记忆中的位表示。因此,例如,如果我想要改变一个有机体,我会随机翻转该对象的位。
首先,我尝试使用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
如果我为^
更正此错误,我会为其他操作员获得更多错误。
我之前没有在代码中使用按位运算符,所以我猜这些运算符不应该与任何对象一起使用?如果是这样,我怎么能解决这个问题?
答案 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();
};