web-dev-qa-db-ja.com

C ++ 11/14でランダムなバイトのデータを効率的に生成する

私の要件は、ランダムなバイトのデータ(乱数ではない)、別名一様分布ビットを生成することです。

そのため、C++ 11/14ランダム機能を使用してこれを行う正しい/効率的な方法は何であるか疑問に思いました。私は例を見回しましたが、それらはall数の生成に焦点を合わせているようです(ints、floatsなど)

私が使用している現在のソリューションは次のとおりです。

#include <vector>
#include <random>

int main()
{
   std::random_device rd;
   std::uniform_int_distribution<int> dist(0,255);
   std::vector<char> data(1000);
   for (char& d : data)
   {
      d = static_cast<char>(dist(rd) & 0xFF);
   }
   return 0;
}
16
Gerdiner

分布はランダムなビットを取り、それらを数値に変換します。実際にランダムビットが必要な場合は、エンジンを使用します。

特に、これらの要件は、可能な各ビット値が均一に発生する可能性が高いビットのシーケンスを生成するタイプおよびオブジェクトのアルゴリズムインターフェイスを指定します。3

URNGオブジェクトへの1回の呼び出しで、多くの(通常は32以上の)ビットを生成および配信でき、これらのビットを符号なし整数型の単一のパッケージ値として返します。4N3847

random_deviceは、一様分布のビットに簡単にアクセスできるように指定されています。

std::random_device engine;
unsigned x = engine(); // sizeof(unsigned) * CHAR_BIT random bits

他のエンジンでは、result_typeが保持できるよりも少ないビットを返すため、または小数ビットを効果的に返すことによって、random_deviceほど均一にランダムなビットを取得するのはそれほど簡単ではない場合があることに注意してください。

unsignedのサイズが実装で定義されているため、random_deviceが実装で定義されたビット数を返すことが懸念される場合は、十分なビットを収集してから提供するアダプターを作成できます。十分なビットを提供し、残りを次のリクエストのためにキャッシュします。 (これを実行して、前述の問題を示す他のエンジンを処理することもできます。)

14
bames53

あなたが探しているのは _std::independent_bits_engine_ アダプターです:

_#include <vector>
#include <random>
#include <climits>
#include <algorithm>
#include <functional>

using random_bytes_engine = std::independent_bits_engine<
    std::default_random_engine, CHAR_BIT, unsigned char>;

int main()
{
    random_bytes_engine rbe;
    std::vector<unsigned char> data(1000);
    std::generate(begin(data), end(data), std::ref(rbe));
}
_

一般的なケースでは、受け入れられた答えは厳密には正しくないことに注意してください。ランダムエンジンは、範囲[min()max()]に属する符号なしの値を生成しますが、これは必ずしもすべての可能な値をカバーするとは限りません。結果タイプ(たとえば、std::minstd_Rand0::min() == 1)であるため、エンジンを直接使用すると、均一に分散されないランダムなバイトが取得される可能性があります。ただし、_std::random_device_の場合、範囲は[std::numeric_limits<result_type>::min()std::numeric_limits<result_type>::max()]であるため、この特定のエンジンはアダプターがなくてもうまく機能します。

30
r_k

あなたの質問に答えるために:あなたはできません。

この標準では、_std::uniform_int_distribution_をchar、_signed char_、または_unsigned char_でテンプレート化することは許可されていません。これは規格の欠陥であると考える人もいますが、実際はそうです。

_std::uniform_int_distribution_で_unsigned short_をテンプレート化し、その最小/最大範囲をstd::numeric_limits<unsigned char>::min()およびstd::numeric_limits<unsigned char>::max()に設定して、結果を_unsigned char_。

標準から:

この26.5節全体を通して、テンプレートをインスタンス化する効果は次のとおりです。

[...]

e)IntTypeという名前のテンプレートタイプパラメータを持つものは、対応するテンプレート引数がcvで修飾されておらず、shortintlongのいずれかでない限り、未定義です。 、_long long_、_unsigned short_、_unsigned int_、_unsigned long_、または_unsigned long long_。

§26.5.1.1[Rand.req.genl]

さらに:

実際にランダムバイトを生成するには、 _std::mt19937_ を使用する必要があります。 _std::random_device_は遅くなる傾向があり、必要のない統計的特性(つまり、暗号化での使用に適している)を備えたエントロピーを生成する可能性があります。

そうは言っても、_std::mt19937_をシードする必要があります。これは、_std::random_device_および _std::seed_seq_ を使用して実行できます。

_std::seed_seq_を使用して_std::mt19937_をシードしない場合、_std::mt19937_の内部状態には多くのゼロが残るため、かなりの時間がかかることに注意してください。 「ウォームアップ」しながら。

「ウォームアップ」の詳細については、 ここを参照