web-dev-qa-db-ja.com

Rand()の実装

Cでいくつかの埋め込みコードを書いているので、Rand()関数を使用する必要があります。残念ながら、Rand()はコントローラーのライブラリではサポートされていません。高速であるが、さらに重要なことに、比較的高品質の乱数を生成するスペースのオーバーヘッドがほとんどない単純な実装が必要です。使用するアルゴリズムやサンプルコードを知っている人はいますか?

編集:それは画像処理用なので、「比較的高品質」とは、適切なサイクル長と優れた均一性を意味します。

19
rlbond

これをチェックしてください 乱数ジェネレーターのコレクション ジョージマルサグリアから。彼は乱数生成の第一人者なので、彼が推奨するものなら何でも使用できると確信しています。そのリストのジェネレーターは小さく、状態として署名されていないlongを2つだけ必要とするものもあります。

マルサリアの発電機は、長期間の基準と良好な均一分布により、間違いなく「高品質」です。暗号化には合格しませんが、厳格な統計的検定に合格します。

23
John D. Cook

Cコード for L'écuyerのLFSR11 を使用します。

unsigned int lfsr113_Bits (void)
{
   static unsigned int z1 = 12345, z2 = 12345, z3 = 12345, z4 = 12345;
   unsigned int b;
   b  = ((z1 << 6) ^ z1) >> 13;
   z1 = ((z1 & 4294967294U) << 18) ^ b;
   b  = ((z2 << 2) ^ z2) >> 27; 
   z2 = ((z2 & 4294967288U) << 2) ^ b;
   b  = ((z3 << 13) ^ z3) >> 21;
   z3 = ((z3 & 4294967280U) << 7) ^ b;
   b  = ((z4 << 3) ^ z4) >> 12;
   z4 = ((z4 & 4294967168U) << 13) ^ b;
   return (z1 ^ z2 ^ z3 ^ z4);
}

非常に高品質で高速です。 Rand()は何にも使用しないでください。役に立たないより悪いです。

11
R Simard

これがANSICへのリンクです いくつかの乱数ジェネレーターの実装

4
Reed Copsey

コンパクトで組み込みシステムに適した乱数ジェネレーター " simplerandom "のコレクションを作成しました。コレクションは [〜#〜] c [〜#〜] および Python で利用できます。

私は見つけたシンプルでまともなものをたくさん探して、それらを小さなパッケージにまとめました。それらには、いくつかのマルサリアジェネレーター(KISS、MWC、SHR3)、およびいくつかのL'EcuyerLFSRジェネレーターが含まれます。

すべてのジェネレーターは符号なし32ビット整数を返し、通常は1〜4個の32ビット符号なし整数で構成される状態になります。

興味深いことに、Marsagliaジェネレーターにいくつかの問題が見つかり、それらすべての問題を修正/改善しようとしました。それらの問題は次のとおりです。

  • SHR3ジェネレーター(Marsagliaの1999 KISSジェネレーターのコンポーネント)が壊れていました。
  • MWCの下位16ビットには約2つしかありません29.1 限目。そこで、わずかに改良されたMWCを作成しました。これにより、下位16ビットに2が与えられます。59.3 期間。これは、このジェネレーターの全体的な期間です。

シードに関するいくつかの問題を発見し、堅牢なシード(初期化)手順を作成しようとしたので、「悪い」シード値を指定しても問題は発生しません。

3
Craig McQueen

メルセンヌツイスター

ウィキペディアから少し:

  • それは2の期間を持つように設計されました19937 − 1(アルゴリズムの作成者がこのプロパティを証明しました)。実際には、ほとんどのアプリケーションは2を必要としないため、より長い期間を使用する理由はほとんどありません。19937 ユニークな組み合わせ(219937 約4.3×10です6001;これは、観測可能な宇宙の粒子の推定数である10よりも何桁も大きいです。80)。
  • それは非常に高次の次元同程度分布を持っています(線形合同法を参照)。これは、出力シーケンスの連続する値の間に無視できるシリアル相関があることを意味します。
  • Diehardテストを含む、統計的ランダムネスの多数のテストに合格します。これは、すべてではありませんが、さらに厳しいTestU01クラッシュランダム性テストのほとんどに合格します。

  • リンクで利用可能な多くの言語のソースコード。

2
Liran Orevi

学術論文をお勧めします 最小標準乱数ジェネレーターの2つの高速実装 DavidCartaによる。 Googleから無料のPDFを見つけることができます。MinimalStandardRandomNumberGeneratorに関する元の論文も読む価値があります。

Cartaのコードは、32ビットマシンで高速で高品質の乱数を提供します。より徹底的な評価については、論文を参照してください。

2
Norman Ramsey

GNU Cライブラリから1つを取得します。ソースは、オンラインで閲覧できます。

http://qa.coreboot.org/docs/libpayload/Rand_8c-source.html

ただし、乱数の品質についてまったく懸念がある場合は、より注意深く記述された数学ライブラリを検討する必要があります。これは大きなテーマであり、標準のRand実装は専門家によってあまり考えられていません。

別の可能性があります: http://www.boost.org/doc/libs/1_39_0/libs/random/index.html

(選択肢が多すぎる場合は、いつでもランダムに1つ選ぶことができます。)

1

私はこれを見つけました: Simple Random Number Generation、by John D.Cook

コードが数行しかないことを考えると、Cに簡単に適応できるはずです。

編集:そしてあなたは「比較的高品質」が何を意味するのかを明確にすることができます。核発射コードの暗号化キー、またはポーカーゲームの乱数を生成していますか?

1
erjiang

さらに良いことに、複数の線形フィードバックシフトレジスタを使用して、それらを組み合わせます。

sizeof(unsigned) == 4と仮定すると:

unsigned t1 = 0, t2 = 0;

unsigned random()
{
    unsigned b;

    b = t1 ^ (t1 >> 2) ^ (t1 >> 6) ^ (t1 >> 7);
    t1 = (t1 >> 1) | (~b << 31);

    b = (t2 << 1) ^ (t2 << 2) ^ (t1 << 3) ^ (t2 << 4);
    t2 = (t2 << 1) | (~b >> 31);

    return t1 ^ t2;
}
1
BenW

標準的な解決策は、 線形フィードバックシフトレジスタ を使用することです。

0
tetromino

[〜#〜] kiss [〜#〜] という名前の単純なRNGが1つあり、3つの数値に応じた1つの乱数ジェネレーターです。

/* Implementation of a 32-bit KISS generator which uses no multiply instructions */ 

static unsigned int x=123456789,y=234567891,z=345678912,w=456789123,c=0; 

unsigned int JKISS32() { 
    int t; 

    y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); 

    t = z+w+c; z = w; c = t < 0; w = t&2147483647; 

    x += 1411392427; 

    return x + y + w; 
}

また、RNGをテストするためのWebサイトが1つあります http://www.phy.duke.edu/~rgb/General/dieharder.php

0
zangw