2012-04-27 9 views
2

外部ライブラリ(ブーストなど)を使わずにstd :: bitset <>をダブルに変換する方法はありますか?私は遺伝的アルゴリズムでゲノムを表現するためにビットセットを使用しています。ビットのセットをダブルに変換する方法が必要です。std :: bitset <64>をダブルに変換するにはどうすればいいですか?

+1

ビットが64ビット整数を表し、それをダブルに変換しますか?(ビットを倍精度浮動小数点数のバイナリ表現として扱うのとは対照的に)。 –

+3

'* reinterpret_cast (&bitset <64> :: to_ullong())'を使用していませんか? – user2k5

+0

@ user2k5:これは、互換性のないポインタ型を使ってオブジェクトをデリファレンスしています...私はC++のルールが何であるか分かりませんが、そのアクションはCの未定義の動作です。 – dreamlax

答えて

5

であるように、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; 
} 

EDIT:コメントで述べたように、それは代わりに、未定義であることの指定されていないとして、我々は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; 
} 

to_ullongには、C++ 11がまだ必要です。

+0

はこのUBではありませんか?ユニオンには、一度に1人のメンバーしか含めることができません。 'd'を起動すると' i'が無効になります。 http://stackoverflow.com/q/10271929/1025391 – moooeeeep

+4

も参照してください。http://stackoverflow.com/questions/6136010/is-using-an-union-in-place-of-a-cast-well-defined 。はい、これはUBですが、これはほとんどのプラットフォームで動作します。あなたはそれに頼りたいですか?誰も答えることのできない質問です。 – PlasmaHH

+0

いいですね。確かに非常に滑らか。 –

1

編集::私はこれで少しばかげていると判断しました。あなたが二重で終わる間、それはビットセットが整数を保持すると仮定します...これは大きな前提です。ビットセットごとに予測可能で反復可能な値になりますが、これは著者が意図したものではないと思います。まあ

あなたはビット値を反復して働くだろう

output_double += pow(2, 64-(bit_position+1)) * bit_value; 

をすれば。限り、それはビッグエンディアン

+0

私はここで '^'は力の演算子でなければならないと思いますか?それはC + +では動作しませんが(代わりにビットシフトを使うことができます)、アルゴリズムも間違っています。 –

+0

アルゴの何が間違っているかを把握しようとしています。私は^を変更しました。...疑似コードで始まりました。投稿前に編集するのを忘れました。編集:アルゴリズムの問​​題を見つけることができません。 – Dennis

+1

'pow'は浮動小数点で動作するので遅すぎます。あなたのアルゴリズムはIEEE形式の 'double'ではなく、整数を変換します。 –

2

ほとんどの人は、エンコードされたintまたはdoubleを直接含んでいるかのようにビットベクトルを処理できるようにするための答えを提供しようとしています。

私はこのアプローチを完全に避けることをお勧めします。作業の定義のために「機能する」とはいえ、どこにでもハミング・クリフが導入されています。 2つのデコードされた値がお互いに近い場合、それらのエンコードされた値がお互いに近くなるようにエンコードすることが通常はエンコードするようにします。また、64ビットの精度を使用する必要があります。

私は手動で変換を管理します。エンコードする変数x、y、zが3つあるとします。あなたのドメインの専門知識は、例えば、-= x < 5,0 0 < = y < 100、および0 < = z < 1であり、xの精度は8ビット、yのビットは12ビット、およびzについては10ビットである。これはわずか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>へ物事をエンコードする。もちろん、このコードにはたくさんのものがありますが、ここには載っていませんが、おそらく基本的な考えを得ることができます。

GPUの計算を行っている場合や、64ビットが適切なサイズになっているような特定の問題がある場合は、すべてをネイティブワードに埋め込む余計なオーバーヘッドになる可能性があります。それ以外の場合は、検索プロセスに追加するオーバーヘッドが、エンコードとデコードの高速化によって得られるメリットを圧倒していると思います。

関連する問題