2012-12-06 19 views
5

私は、コードのこれら2つのブロックが異なる出力与えるなぜわからない午前:C(ランダム)&SETSTATE機能が期待通りに動作しない

unsigned int seed1 = 0; 
char state1[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
setstate(state1); 
printf("%10ld\n", random()); 
// Gives: 
// 1216130483 
// 625602885 

は私が何SETSTATE誤解アム

unsigned int seed1 = 0; 
char state1[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
printf("%10ld\n", random()); 
// Gives: 
// 1216130483 
// 1950449197 

対を()ありますか?

EDIT:興味深いことに 、これは与えるものを見て:

unsigned int seed1 = 0; 
char state1[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
setstate(state1); 
setstate(state1); 
printf("%10ld\n", random()); 
// Gives: 
// 1216130483 
// 1950449197 
+1

Cのみ 'rand'と' srand'とどちら 'random'、' initstate'または 'setstate'を持っています。あなたの質問にOSにタグを付けてください。 –

+1

@JensGustedt bsdタグを追加しました。 – unwind

+0

'gcc(Debian 4.4.5-8)4.4.5を使ってDebian(安定版)でこの例を実行すると、3つのコードスニペットすべてで同じ2つの数字が得られます。 – alk

答えて

2

私はinitstate()への呼び出しもその状態に切り替わらないと思いますが、setstate()への呼び出しが、なぜ後者である、ありませんrandom()呼び出しは、新しい状態から生成された番号を返します。

+2

コードを少し試してみましたが、これは当てはまりません。 'initstate()'の直後に 'setstate()'を呼び出すと、何の違いもありません。 – NPE

3

どちらの実装も正しいです。

Setstateは、バッファ内を指すようにルーチン内の静的ポインタを変更するだけです。

Initstateは同じことをすることができますが、最初にバッファの内容を変更することもできます。 PRNGがARC4またはSpritzのようなものであれば、バッファは任意のビットではなく順列である必要があります。 PRNGが非線形加算フィードバック生成器である場合、状態のどこかの低位ビットの少なくとも1つを設定する必要があり、そうでないと正しく動作しません。また、いくつかのlibsは状態バッファをハッシュするので、どの種のPRNGがシード+出力情報から使用されているのかを簡単には分かりません。彼らは必須ではありません。 libはinitstateとsetstateに対して、使用するジェネレータが特定のフォーマットを必要とせず、バッファの整合性を必要とするLFSGなどのものであれば、まったく同じことを行うことができます。しかし、initstateを実行しておらず、OSがそのようなニーズを持つものを使用している場合、反復可能なシーケンスは、望むほど予測できないことがあります。

2

setstateのBSD実装は、エラーチェックの目的で、古いバッファに格納する前に補助状態情報をロードします。さらに、initstateおよびsetstateは、この情報を更新する唯一の機能です。つまり、同じバッファを使用した場合、loads stale statestores the new data、およびupdates the internal state with the formerとなります。このようにしてsetstateを繰り返し呼び出すと、古い格納状態と現在の内部状態が交互に変更され、2回呼び出されたときに結果が観察されます。

The comment for setstateは、現在のバッファでそれを呼び出すことはOKであるため、これは意図した動作か、decades oldのバグです。

setstate()を現在の状態と同じ状態で呼び出しても問題ありません。

1

initstate()は、次の乱数 の情報を格納するために使用するバッファをランダムに示します。バッファstate1[256]の情報が変更されたため、random()へのコールで異なる回答が得られます。次のコードの出力を見てください:

#define LEN (32) 
void print_hex(char *b) 
{ 
    int i; 
    for(i=0; i < LEN; i++) printf("%02x ",((unsigned char *)b)[i]);  
    printf("\n"); 
} 

main() 
{ 
    char state1[256], state2[256], tmp[256]; 
    initstate(42, state2, LEN); 
    initstate(62, state1, LEN) ; 
    printf("buffer before random():\n"); 
    print_hex(state1) ; 
    printf("%10ld\n", random()); 
    printf("buffer after random():\n"); 
    print_hex(state1) ; 

    setstate(state2); // Now we are free to copy data from state1 
    printf("buffer after setstate():\n"); 
    print_hex(state1) ; 
    memcpy(tmp, state1, 256); 
    printf("copied to tmp\n"); 

    setstate(state1); // Go on with original sequence 
    printf("next random():\n") ; 
    printf("%10ld\n", random()); 
    printf("next random():\n") ; 
    printf("%10ld\n", random()); 

    setstate(state2) ; // Again, this allows us to play with data in state1 
    memcpy(state1, tmp, 256); 
    setstate(state1) ; 
    printf("back copy:\n"); 
    printf("random() after copy:\n") ; 
    printf("%10ld\n", random()); 
    printf("next random():\n") ; 
    printf("%10ld\n", random()); 
} 

は、これは、出力を与える:あなたはrandom()に最初の呼び出しの後のバッファstate1変更の内容を見ることができることを

buffer before random(): 
01 00 00 00 e7 22 1d 21 f1 62 9c 90 89 72 b5 89 35 2b 97 b5 76 8c ff a8 56 14 14 7b ba 19 d9 f7 
1801070350 
buffer after random(): 
01 00 00 00 e7 22 1d 21 f1 62 9c 90 89 72 b5 89 1c 4e b4 d6 76 8c ff a8 56 14 14 7b ba 19 d9 f7 
buffer after setstate(): 
06 00 00 00 e7 22 1d 21 f1 62 9c 90 89 72 b5 89 1c 4e b4 d6 76 8c ff a8 56 14 14 7b ba 19 d9 f7 
copied to tmp 
next random(): 
483260339 
next random(): 
    40158063 
back copy: 
random() after copy: 
483260339 
next random(): 
40158063 

random()はその領域を使用してその状態を格納します。この状態はバッファtmpにコピーされます。後でstate1にコピーし、乱数の同じシーケンスを取得します。 乱数に使用するはずのバッファーにコピーする前に、またはまたはinitstate()を使用して、そのバッファーの使用を停止するようにrandom()に指示する必要があります。その理由は、setstate()が呼び出されたときに古いバッファが変更され、setstate()で再度ロードされるようにするためです。

だから、元の質問と同じ答えを得るために、あなたが使用する必要があります:

unsigned int seed1 = 42; 
char state1[256], tmp[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
initstate(0, tmp, 256); // <- notice this 
setstate(state1) ; 
printf("%10ld\n", random()); 
関連する問題