Diehardテストに合格する乱数ジェネレーターを構築する


50

ここにはランダム性に関する多くのコードゴルフの質問がありますが、実際にはアルゴリズムの擬似乱数ジェネレータの構築を要求するものはまだ見ていません。ビットストリームを生成するように要求するものがありますが、その1つで提供されるランダム性テストはそれほど厳密ではなく、コードゴルフでもありません。

作成するプログラムには、0〜4294967295のランダムな整数を返す呼び出し可能な関数が1つあります。この関数は、プログラムの一部としても記述されていないライブラリや他の関数、特に/ dev / randomの呼び出しを呼び出してはなりませんまたは、言語の組み込みrand()ライブラリ。より具体的には、算術、配列アクセス、条件付きフロー制御ステートメントなど、使用している言語の基本的な演算子に制限されます。

プログラムのスコアは次のように計算されます。

Score = C / R

Cは文字単位のコードの長さで、RはジェネレーターがパスするDiehardテストの数です(乱数ジェネレーターが少なくとも1つのDiehardテストにパスしない場合、スコアは無限であり、失格となります)。ジェネレーターは、生成するファイルが区間[0、1)に沿って均一に分布しているように見えるP値の範囲を提供する場合、ダイハードテストに合格します。

Rを計算するには、乱数ジェネレーターとそのデフォルトシードを使用して、16 MBのバイナリデータファイルを生成します。関数の各呼び出しは4バイトを返します。関数が遅すぎてバイトを返せない場合は、テストの難易度によって低スコアを達成するためのトレードオフが考慮されます。次に、Diehardテストを実行し、提供されたP値を確認します。(これらを自分で実装しようとしないでください。ここで提供されているものを使用してください

もちろん、最低スコアが勝ちます。


インターネット接続を必要とするコードは許可されていますか?(ランダム関数にオンラインでアクセスするつもりはありませんが、pingまたはAPI呼び出しの値)
elssar

「この関数は、プログラムの一部としても記述されていないライブラリーまたは他の関数を呼び出さないでください。」これには、インターネット接続機能が含まれます。あなたの世代は純粋にアルゴリズムでなければなりません。
ジョーZ.

diehardスイートでは、10〜11 MBの入力ファイルが必要です。
primo

テストへのリンクが壊れているように見えますが、これは可能な代替案です。
-2012rcampion

私の頭脳の答えのためにこれをどのように行うべきですか?コードが遅すぎて実用的ではないと思う
クリストファー

回答:


6

Mathematica、32/15 = 2.133

x=3;Mod[x=Mod[x^2,28!-67],2^32]&

BBSの簡単な実装。

以下で生成されたバイナリファイル:

f = %; (* assigns anonymous function declared in the previous expression to f *)
Export["random.bin", Array[f, 2^22], "UnsignedInteger32"];

結果の要約:

 1. BIRTHDAY SPACINGS TEST           .684805
 2. OVERLAPPING 5-PERMUTATION TEST   .757608/.455899
 3. BINARY RANK TEST                 .369264/.634256
 4. BINARY RANK TEST                 .838396
 5. THE BITSTREAM TEST                (no summary p-value)    
 6. OPSO, OQSO and DNA                (no summary p-value)
 7. COUNT-THE-1's TEST               .649382/.831761
 8. COUNT-THE-1's TEST                (no summary p-value)
 9. PARKING LOT TEST                 .266079
10. MINIMUM DISTANCE TEST            .493300
11. 3DSPHERES TEST                   .492809
12. SQEEZE                           .701241
13. OVERLAPPING SUMS test            .274531
14. RUNS test                        .074944/.396186/.825835/.742302
15. CRAPS TEST                       .403090/.403088/.277389

random.binここでいっぱい。

完全なログファイルはこちら。


28!-67やや法外です。64ビット整数に収まる小さな値はありますか?
プリモ

@primo Pythonと同様に、Mathematicaの整数はデフォルトで任意精度であるため、問題は発生しません。
-2012rcampion

私は特にCへの移植性を考えていました。
primo16年


21

Perl 28/13≈2.15

sub r{$s^=~($s^=$s/7215)<<8}

ログファイルはこちら

Perl 29/13≈2.23

sub r{$s^=~($s^=$s<<8)/60757}

ログファイルはこちら

これらは、右シフトの代わりに浮動小数点除算を使用するXorshiftのバリエーションです。両方とも15のテストのうち13に合格し、テスト6と7のみに失敗します。

サイクルの長さは正確にはわかりませんが、次のコードは短期間で終了しないため、おそらく完全な2 32になります。

$start = r();
$i++ while $start != r();
print $i;

Perl 39/10 = 3.9

$s=$^T;sub r{~($s=$s*$s%4294969373)||r}

注:Blum-Blum-Shub風のPRNGを探している場合、Keith Randallのソリューションはこれらのいずれよりもはるかに優れています。

以下の元のソリューションと同様に、これはBlum Blum Shubの実装でもありますが、大きな違いが1つあります。私は2 32よりわずかに大きいモジュラス(M = 50971•84263)を使用し、値が有効な32ビット整数でない(つまり、2 32より大きい)場合は、次の値を返します代わりに回転。本質的に、これらの値は取り除かれ、残りの回転はそのままにされ、ほぼ均一な分布が得られます。

助けたようです。以前と同じ9つのテストに合格することに加えて、最小距離テストにも確実に合格しました。サンプルログファイルはこちらにあります


Perl 33/9≈3.67(無効ですか?)

 $s=$^T;sub r{$s=$s*$s%4294951589}

注:範囲の最上位0.00037%は決して観察されないため、このソリューションは無効と見なされる場合があります。

Blum Blum Shubの迅速で汚れた実装。私は次の結果を主張しています:

 1. passed - Birthday Spacings
 2. FAILED - Overlapping Permutations
 3. passed - Ranks of 31x31 and 32x32 Matrices
 4. passed - Ranks of 6x8 Matrices
 5. FAILED - Monkey Tests on 20-bit Words
 6. FAILED - Monkey Tests OPSO, OQSO, DNA
 7. FAILED - Count the 1s in a Stream of Bytes
 8. passed - Count the 1s for Specific Bytes
 9. passed - Parking Lot Test
10. FAILED - Minimum Distance Test
11. passed - Random Spheres Test
12. FAILED - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test

サンプルログファイルはこちらにあります。結果については、お気軽にご相談ください。diehardのファイルは、次の方法で生成できます。

print pack('N', r()) for 1..4194304

そして、出力をファイルにパイプします。最小距離は通過したように見えますが、複数回実行すると、常に1.0に非常に近くなり、失敗を示します。


詳細

一般に、Blum Blum ShubはひどいPRNGですが、適切なモジュラスを選択することでパフォーマンスを改善できます。M Iは、選択した7027•611207。これらの素因数pqは両方ともモジュラー剰余3(mod 4)であり、gcd(φ(p-1)、φ(q-1))= 2であり、可能な限り低くなっています。

これらはwikiページにリストされている唯一の基準ですが、それだけでは十分ではないようです。私が試したほとんどすべてのモジュロは、すべてのテストに失敗しました。しかし、いくつかのテストに合格する少数のテストがあり、私が選択したテストは、何らかの理由で非常に優れているようです。

最後の注意として、テスト5自体はPRNGがどれだけ優れているかのかなり良い指標であるようです。テスト5にほとんど合格しない場合、残りのテストは見事に失敗します。


ボーナス:Perl 62/14≈4.43

$t=$^T;sub r{$t|=(($s=$s/2|$t%2<<31)^($t/=2))<<31for 1..37;$t}

おたくだけのために、これは元のTetris for NESで使用されているPRNGの32ビットバージョンです。驚いたことに、15のテストのうち14をパスしています!

 1. passed - Birthday Spacings
 2. passed - Overlapping Permutations
 3. passed - Ranks of 31x31 and 32x32 Matrices
 4. passed - Ranks for 6x8 Matrices
 5. passed - Monkey Tests on 20-bit Words
 6. passed - Monkey Tests OPSO, OQSO, DNA
 7. FAILED - Count the 1s in a Stream of Bytes
 8. passed - Count the 1s for Specific Bytes
 9. passed - Parking Lot Test
10. passed - Minimum Distance Test
11. passed - Random Spheres Test
12. passed - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test

サンプルログファイルはここより前にできます

確かに、この1..37ビットは正確な転写ではありません。元のバージョンでは、エントロピールーチンは1秒間に60回更新され、ユーザー入力に大きく依存してランダムな間隔でクエリされます。ROMを分解したい人のために、エントロピールーチンはから始まります0xAB47

Pythonスタイルの擬似コード:

carry = entropy_1 & 1
entropy_1 >>= 1
entropy_2 = (entropy_2 >> 1) | (carry << 31)
carry = (entropy_1 & 1) ^ (entropy_2 & 1)
entropy_1 |= carry << 31

ええ、私はあなたのアルゴリズムがビットストリームテストに「失敗」したことに気付きましたが、実際には0.999999未満のいくつかの値がありました。それでも、テストは正確に見えます。
ジョーZ.

ただし、1つの問題があります。それは、4294951589から4294967295までの数値が発生する可能性がないことです(ただし、Diehardのテストのいくつかが失敗した理由の一部だと思います)。
ジョーZ.

1
@JoeZengはい、それは問題です。テスト5で最も明らかです。最初の実行で欠落している単語は151kで、残りは143kしか欠落していません。1つの解決策は、2 ^ 32よりわずかに大きいモジュラスを選択し、大きすぎてゼロに折り返すことができないようにすることですが、うまく機能するものを見つけることができませんでした。もしそうなら、投稿を更新します。
primo

7

Python、46/15 = 3.0666

v=3
def R():global v;v=v**3%(2**32-5);return v

モジュラーべき乗を使用して、ランダム性を生成します。2 ** 32-5は、2 ^ 32より小さい最大の素数です。(テスト#2を実行できないことと同じ対処。)


ログファイルを貼り付けていただけますか?
primo

ここにログイン:codepad.org/ZWhoGe0t
キースランドール

1
愚かなウィンドウ。\rおよびのすべての出現をに変換していた\nため\r\n、明らかに結果が歪んでいます。修正方法は、f = open('file.bin', 'wb')とを使用してファイルを直接書き込むことですf.write
プリモ

この新しいスコアは以前のスコアよりも低いので、今では受け入れられている答えです。
ジョーZ.

この新しいスコアは再びアンダーカットされたため、受け入れられた回答を変更しました。
ジョーZ.

4

ルビー、32/15 = 2.1333

これは、Rubyで実装されたキースランドールのソリューションです。

$v=3;def R;$v=$v**3%(2**32-5)end

@JoeZこれは新しいMathematicaの答えと結びついた新しい最低の答えのようです。
ライキング

3

C#144/15 = 9.6

uint a=15,b=26,y;uint q(int n){y=(a*1414549U+876619U)^(b*889453U+344753U);b=a;a=y>>12;return(a%256)<<n;}uint r(){return q(24)|q(16)|q(8)|q(0);}

これはすべてのテストに合格しました。

文字数があまり多くないため、TestU01に合格します。

結果:http : //codepad.org/iny6usjV

    uint a = 15;
    uint b = 26;

    byte prng8()
    {
        uint y = ((a * 1414549U + 876619U) ^ (b * 889453U + 344753U)) >> 12;
        b = a;
        a = y;
        return (byte)y;
    }

    uint prng32()
    {
        return ((uint)prng8() << 24) | ((uint)prng8() << 16) | ((uint)prng8() << 8) | (uint)prng8();
    }

2

C#-103/14 = 7.36

double j=999;uint N(){uint i=0,n=0;for(;i++<4;n=n*256+(uint)j%256)for(j/=277;j<100000;j*=j);return n;}

結果

テスト#6
を除くすべてに合格http://codepad.org/k1NSoyQWの結果を参照

説明

C#は、いつものように簡潔さを求めてRubyやPythonと競合することはできませんが、試してみました。同様に機能する他の値も確かにあります(つまり、j = 999の初期値、およびdivisor = 277)。簡単な実験の後にこれらを選びました。

ファイル作成ラッパー付き

class R
{
    public static void Main(string[] args)
    {
        var r = new R();
        using (var f = new System.IO.FileStream(".\\out.bin", System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read))
        using (var b = new System.IO.BinaryWriter(f))
        {
            for (long i = 0; i < 12 * 1024 * 1024; i += 4)
            {

                b.Write(r.N());
            }
        }
    }

    double j = 999;

    uint N()
    {
        uint i = 0, n = 0;
        for (; i++ < 4; n = n * 256 + (uint)j % 256)
            for (j /= 277; j < 100000; j *= j) ;
        return n;
    }

}

1

Python、41/15 = 2.73333

v=0
def R():global v;v=hash(`v`);return v

ちょっとハッシュ関数を内蔵していないが、それを使用して不正行為をされ、内蔵なので、これ以上のように、他の組み込みコマンドを使用するよりも浮気をlen。反対に、global v;声明の支払いが必要になるのは苦痛です...

すべてのDiehardテストに合格します(テスト#2で問題が発生し、OSXマシンでSEGVが発生しました。私のスコアでは、合格すると想定しています)。

16MBファイルを生成するドライバーは次のとおりです。

import sys
for i in xrange(1<<22):
  r=R()
  sys.stdout.write('%c%c%c%c'%(r&255, r>>8&255, r>>16&255, r>>24&255))

「この関数は、プログラムの一部としても記述されていないライブラリや他の関数、特に/ dev / randomまたは言語の組み込みrand()ライブラリへの呼び出しを呼び出してはなりません。」申し訳ありませんが、それはあなたの応募資格を失います。
ジョーZ.

明確にするために、「len」もあなたのエントリーを失格にします。
ジョーZ.

どこで線を引きますか?された+機能を内蔵しており、それゆえ失格しますか?
キースランドール

6
しかし、多くの言語では、演算子と関数は同一です。Pythonの+and __add__、またはc ++の演算子のオーバーロードを参照してください。私は髪の毛を割っているのを知っているので、この例を考えてみてください。Pythonでは、次のようなマップを作成でき{'a':5}ますか?おそらく「はい」と言うでしょうが、それhash('a')を行うと、隠れて呼び出されることを考慮してください。
キースランドール

2
そのように関数を構文的に参照する必要があるときに、線を引くと思います。Pythonで、「ハッシュ」関数を構文的に参照せずにマップアドレスに直接アクセスできるハックを見つけることができれば、それを受け入れるかもしれません。
ジョーZ.

1

C、38/15 = 2.533

long long x;f(){return(x+=x*x+9)>>32;}

マシン上でDiehardテストを動作させることはできませんでしたが、最大8GBの出力のPractRandスイートに合格するため、すべてに合格すると想定しています。


0

Brain-Flak、344 /(保留中)

<>((()()){})<> push the amount of iterations to do for the PRNG
(((((((((((((((((((((((((((((((((((()()()){}()){})){}{}){()()()()({}[()])}{})){}{})){}{})()){}{})()){}{})){}{})){}{}){}())){}{})){}{})()){}{})()){}{})){}{})){}{})()){}{})()){}{}) push M (one of the values for the Blum Blum Shub PRNG
((((((((((((()()()){}){}){})){}{}){()({}[()])}{}){}())){}{})()){}{}) push s see above
<>{({}[()])<>starts the loop
(({({})({}[()])}{}) squares the current number
(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]({}))mods by M
<>}{}<>loop ends

オンラインでお試しください!

これは正常に機能しますが、頑固なテストのリンクはすべて壊れています:(したがって、新しいものを取得するまで、最終スコアはありません

これは、Blum Blum Shub PRNGを使用するため、ほとんどの場合に合格します。使用される数値は十分に大きく、16 MBのテストケース内にパターンは表示されません。


これが無効な場合は教えてください
クリストファー

1
私は344を数えます。定理:完全にゴルフされたBrain-flakプログラムは奇数バイトを持ちません。
user202729

0

Objective-C、40/1 = 40

かなり巧妙なアプローチ、.hashここで多少のチートを悪用していますが、私はそれが好きです

for(int v=9;v=@(v).hash;printf("%i",v));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.