2017-11-06 29 views
1

cでPCG乱数ジェネレータを実装しようとしています。私が初心者であるので、例の周りを頭で囲むのは難しいことです。これまでは、hereという最小限のバージョンを実装しようとしました。ここでc:PCGインプリメンテーションを使用して乱数を生成する

は現在、いくつかの(たぶん)擬似乱数を生成し、私のコードです:

#include <stdio.h> 
#include <stddef.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <stdbool.h> 
#include <time.h> 
#include <string.h> 
#include <math.h> 

#include "pcg_basic.h" 

int main(int argc, char** argv){ 
    pcg32_random_t rngptr; 
    pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr); 

    for (int round = 1; round <= 10; ++round) { 
     printf(" %f\n", ldexp(pcg32_random_r(&rngptr) ,-32)); 
    } 

    return 0; 
} 

があっても良い実装であるか、これをよりよく改善することができますか?

問題:main()の機能だけでなく、コード内のどこでも乱数を使用したいと思います。これどうやってするの?私は試みました:

double myrand(){ 
     pcg32_random_t rngptr; 
     pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr); 
     return ldexp(pcg32_random_r(&rngptr) ,-32); 
} 

しかし、このアプローチはうまくいかず、私には間違っています。しかし私はそれをより良くする方法を知らない。

誰かが、コードのあらゆる部分でうまくいく、Cで正しい疑似乱数を得るための簡単な方法を教えてもらえますか?これらの行を見て、あなたが使用して実装を知らなくても

+0

初期化フラグが必要です。それ以外の場合は、同じ番号を何度も何度も繰り返します。 –

+0

PCGの*実装*が表示されません。**は**を使用しています。 –

+0

"*誰か私にc *" < - ここであなたは "良い"を定義する必要があります良い擬似乱数を得るための簡単なアプローチを表示してください。ほとんどの標準的なC実装の 'rand()'は、少なくともゲームでは「十分」です。 –

答えて

2

double myrand(){ 
     pcg32_random_t rngptr; 
     pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr); 
     return ldexp(pcg32_random_r(&rngptr) ,-32); 
} 

二行目乱数ジェネレータ。すべての呼び出しでこれを行うと、実際のP​​RNGは無効になります。

すべてのPRNGは、内部状態を保持し、多かれ少なかれ複雑な算術演算を使用して前の状態から次の状態を計算することによって動作します。次に、内部状態の一部が次の「ランダム」番号として返されます。

内部状態はどこかを開始するために持っているとして、あなたは正確に一度シードすべてのPRNG (およびすべての実行時にどこか違う開始するには、それのためにtime()のようなものを使用)する必要があります。このコードの

簡易版は、したがって、次のようになります。

double myrand(){ 
    static int initialized = 0; 
    static pcg32_random_t rngptr; 
    if (!initialized) 
    { 
     pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr); 
     initialized = 1; 
    } 
    return ldexp(pcg32_random_r(&rngptr) ,-32); 
} 

PRNG(pcg32_random_t変数によって表される)のインスタンスが1つだけプログラム全体にありますので、これはもはや、スレッドセーフではありません。

もう一つの方法は、あなたの関数が実際に(例えば、一度main()で)あなたのPRNGへのポインタを取り、作成を管理し、外部のどこかに播種するために、次のようになります。

double myrand(pcg32_random_t *rngptr){ 
    return ldexp(pcg32_random_r(rngptr) ,-32); 
} 


int main(void) 
{ 
    // do this once: 
    pcg32_random_t rngptr; 
    pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr); 

    // [...] 

    double x = myrand(&rngptr); 
} 

基本的に同じことが適用されますC標準機能srand()rand():PRNGをシードするためには、srand()を正確に1回呼び出す必要があります。これらの関数では、内部状態はstatic(C標準ライブラリ内)なので、何も渡す必要はなく、これらの関数を使用するとスレッドセーフではありません。

ここでは多分、より良いPRNGの一般的な概念を理解するのに役立つ可能性があり0x7fffffffRAND_MAXのための標準C rand()、の非常にシンプルで愚かな実装例です:あなたが見ることができるように

static unsigned long long int randval = 1; 

void srand(unsigned int seed) 
{ 
    randval = seed; 
} 

int rand(void) 
{ 
    randval *= 1103515245; 
    randval += 12345; 
    return (int)((randval/65536) & 0x7fffffff); 
} 

randvalは秘密にしておきますが、srand()を呼び出すと、それが設定されますので、次の呼び出しの結果はrand()になります。

+0

あなたの最初の解決策は簡単に見えますが、秒は速く見えます。実際にポインタを渡さずに乱数を得る方法はありますか? – Samuel

関連する問題