外部ライブラリ(Boostなど)を使用せずにstd :: bitset <64>をdoubleに変換する方法はありますか?遺伝的アルゴリズムでゲノムを表すためにビットセットを使用していますが、ビットのセットをdoubleに変換する方法が必要です。
3 に答える
C++11 の道:
union Converter { uint64_t i; double d; };
double convert(std::bitset<64> const& bs) {
Converter c;
c.i = bs.to_ullong();
return c.d;
}
編集:コメントに記載されているように、char*
未定義ではなく未指定であるため、エイリアシングを使用できます。
double convert(std::bitset<64> const& bs) {
static_assert(sizeof(uint64_t) == sizeof(double), "Cannot use this!");
uint64_t const u = bs.to_ullong();
double d;
// Aliases to `char*` are explicitly allowed in the Standard (and only them)
char const* cu = reinterpret_cast<char const*>(&u);
char* cd = reinterpret_cast<char*>(&d);
// Copy the bitwise representation from u to d
memcpy(cd, cu, sizeof(u));
return d;
}
には引き続き C++11 が必要ですto_ullong
。
ほとんどの人は、ビットベクトルを、エンコードされた int または double が直接含まれているかのように扱うことができる回答を提供しようとしています。
そのアプローチを完全に避けることをお勧めします。作業の定義によっては「機能」しますが、いたるところにハミングクリフが導入されます。通常、2 つのデコードされた値が互いに近い場合、それらのエンコードされた値も互いに近くなるように、エンコードを調整する必要があります。また、64 ビットの精度を使用する必要があります。
手動で変換を管理します。エンコードする 3 つの変数 x、y、z があるとします。ドメインの専門知識を使用して、たとえば、-5 <= x < 5、0 <= y < 100、および 0 <= z < 1 と言うことができます。ここで、x には 8 ビットの精度、y には 12 ビットの精度が必要です。 、および z の 10 ビット。これにより、わずか 30 ビットの合計検索スペースが得られます。30 ビット文字列を使用できます。最初の 8 を x として、次の 12 を y として、最後の 10 を z として扱います。また、ハミングクリフを削除するために、それぞれを自由にグレーコード化することもできます。
私は過去に個人的に次のことを行いました。
inline void binary_encoding::encode(const vector<double>& params)
{
unsigned int start=0;
for(unsigned int param=0; param<params.size(); ++param) {
// m_bpp[i] = number of bits in encoding of parameter i
unsigned int num_bits = m_bpp[param];
// map the double onto the appropriate integer range
// m_range[i] is a pair of (min, max) values for ith parameter
pair<double,double> prange=m_range[param];
double range=prange.second-prange.first;
double max_bit_val=pow(2.0,static_cast<double>(num_bits))-1;
int int_val=static_cast<int>((params[param]-prange.first)*max_bit_val/range+0.5);
// convert the integer to binary
vector<int> result(m_bpp[param]);
for(unsigned int b=0; b<num_bits; ++b) {
result[b]=int_val%2;
int_val/=2;
}
if(m_gray) {
for(unsigned int b=0; b<num_bits-1; ++b) {
result[b]=!(result[b]==result[b+1]);
}
}
// insert the bits into the correct spot in the encoding
copy(result.begin(),result.end(),m_genotype.begin()+start);
start+=num_bits;
}
}
inline void binary_encoding::decode()
{
unsigned int start = 0;
// for each parameter
for(unsigned int param=0; param<m_bpp.size(); param++) {
unsigned int num_bits = m_bpp[param];
unsigned int intval = 0;
if(m_gray) {
// convert from gray to binary
vector<int> binary(num_bits);
binary[num_bits-1] = m_genotype[start+num_bits-1];
intval = binary[num_bits-1];
for(int i=num_bits-2; i>=0; i--) {
binary[i] = !(binary[i+1] == m_genotype[start+i]);
intval += intval + binary[i];
}
}
else {
// convert from binary encoding to integer
for(int i=num_bits-1; i>=0; i--) {
intval += intval + m_genotype[start+i];
}
}
// convert from integer to double in the appropriate range
pair<double,double> prange = m_range[param];
double range = prange.second - prange.first;
double m = range / (pow(2.0,double(num_bits)) - 1.0);
// m_phenotype is a vector<double> containing all the decoded parameters
m_phenotype[param] = m * double(intval) + prange.first;
start += num_bits;
}
}
おそらくあなたには関係のない理由で、私はビット ベクトルを使用していなかったことに注意してくださいvector<int>
。そしてもちろん、ここには示していないこのコードに関連するものがたくさんありますが、基本的な考え方は理解できるでしょう。
もう 1 つ注意してください。GPU 計算を行っている場合、または 64 ビットがとにかく適切なサイズであるなどの特定の問題がある場合は、すべてをネイティブ ワードに詰め込むために追加のオーバーヘッドが必要になる場合があります。そうしないと、検索プロセスに追加するオーバーヘッドが、エンコードとデコードの高速化によって得られるメリットを圧倒してしまうと思います。
編集::私はこれで少しばかげていると判断しました。double になってしまいますが、ビットセットが整数を保持していると想定しています...これは大きな前提です。ビットセットごとに予測可能で再現可能な値になりますが、それでもこれが作者の意図したものだとは思いません。
ビット値を反復処理して実行する場合
output_double += pow( 2, 64-(bit_position+1) ) * bit_value;
それはうまくいくでしょう。ビッグエンディアンである限り