2011-10-27 12 views
19

このコードが<random>ヘッダーをC++ 11で使用しようとしたときに[0, 2**62 - 1]に正しく乱数を生成していますが、[0, 2**63 - 1]または[0, 2**64 - 1]では正しくない理由を理解できません。uniform_int_distribution <uintmax_t>は62ビット数では機能しますが、63ビットまたは64ビットでは機能しないのはなぜですか?

#include <iostream> 
#include <stdint.h> 
#include <random> 
#include <functional> 
#include <ctime> 

static std::mt19937 engine; // Mersenne twister MT19937 

void print_n_random_bits (unsigned int n); 

int main (void) { 
    engine.seed(time(0)); 
    print_n_random_bits(64); 
    print_n_random_bits(63); 
    print_n_random_bits(62); 
    return 0; 
} 

void print_n_random_bits (unsigned int n) 
{ 
    uintmax_t max; 

    if (n == 8 * sizeof(uintmax_t)) { 
    max = 0; 
    } else { 
    max = 1; 
    max <<= n; 
    } 
    --max; 

    std::uniform_int_distribution<uintmax_t> distribution(0, max); 

    std::cout << n << " bits, max: " << max << std::endl; 
    std::cout << distribution(engine) << std::endl; 
} 

は今、もう少し掘りは正しい動作を有し、std::mt19937_64を明らかにしたが、62ビットの数のために働く何かが64ビットの1のために動作しません、なぜ誰も私に説明できますか?

を編集してください。申し訳ありませんが、私は問題を特定しませんでした。 問題は、63ビットおよび64ビットの最大値のため、出力は例えば、一貫範囲[0, 2**32 - 1]内数であるということである。

% ./rand      
64 bits, max: 18446744073709551615 
1803260654 
63 bits, max: 9223372036854775807 
3178301365 
62 bits, max: 4611686018427387903 
2943926730538475327 

% ./rand         
64 bits, max: 18446744073709551615 
1525658116 
63 bits, max: 9223372036854775807 
2093351390 
62 bits, max: 4611686018427387903 
1513326512211312260 

% ./rand              
64 bits, max: 18446744073709551615 
884934896 
63 bits, max: 9223372036854775807 
683284805 
62 bits, max: 4611686018427387903 
2333288494897435595  

編集2:私はclang++Apple clang version 2.1 (tags/Apple/clang-163.7.1))を使用し、「libcのよ++ "私のバージョンはc++0xをサポートしていないので、私は上記のGCCで簡単にテストすることはできません。

+0

これはまさにそれが予期しないことですか?つまり、あなたの期待と異なる結果をあなたにどのくらい提示しているのですか? – andand

+0

また、どの標準ライブラリ実装を使用していますか? – Fanael

+4

多分ちょうど悪いことを考えてみてください:) – Dani

答えて

23

あなたはlibC++にバグを発見しました。ありがとう!!!

私は先端のトランクのリビジョン143104に次の修正を犯した:

Index: include/algorithm 
=================================================================== 
--- include/algorithm (revision 143102) 
+++ include/algorithm (working copy) 
@@ -2548,7 +2548,7 @@ 
     { 
      __u = __e_() - _Engine::min(); 
     } while (__u >= __y0_); 
-  if (__w0_ < _EDt) 
+  if (__w0_ < _WDt) 
      _S <<= __w0_; 
     else 
      _S = 0; 
@@ -2561,7 +2561,7 @@ 
     { 
      __u = __e_() - _Engine::min(); 
     } while (__u >= __y1_); 
-  if (__w0_ < _EDt - 1) 
+  if (__w0_ < _WDt - 1) 
      _S <<= __w0_ + 1; 
     else 
      _S = 0; 

この修正プログラムはバイナリのlibC++の再コンパイルを必要としないdylibを。

+0

うわー、速い仕事! Howardに感謝します。 – Nick

+0

libC++で使用されているアルゴリズムには、それを読むための既知の名前がありますか? –

+2

私は分かりません。このアルゴリズムは、independent_bits_engineの標準仕様で指定されています。 –

0

std::mt19937は32ビット版であるため、次の番号を生成するときに「作業領域」でどのビットが重要かどうかを前提にしている可能性があります。これにより、最後の2ビットを含む可能性のある数を生成するときにオーバーフローが生じます。実際のディストリビューションが32ビットエンジンの2**32 - 1よりも高い最大値を持つ実際には一様ではないことがわかりました。

+0

これについてはわかりません。簡単な調査によれば、分布は、1,000,000個の生成された整数に基づいて、「2 ** 62 - 1」の最大値を持つ一様であるか、またはそれに近いものであることが示唆される。 – Nick

+1

'mt19937'が32ビットの数値を返すとしても、' uniform_int_distribution'はそれを複数回呼び出して62/63/64ビットの数値を生成してはいけませんか? – interjay

関連する問題