2011-07-22 27 views
11

C/C++では、ランダムな整数を取得するときに通常rand()srand()が使用されます。しかし、自分で書き直そうとしたときに、アルゴリズムを理解するのが難しいことが分かりました。関数は数行で非常に簡単に書かれますが、数式は誤解です。Visual C++のrand()関数のアルゴリズムを理解する

メイン式:

ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L; 

オリジナルコード関与:

void __cdecl srand (unsigned int seed) 
{ 
    _getptd()->_holdrand = (unsigned long)seed; 
} 

int __cdecl rand (void) 
{ 
    _ptiddata ptd = _getptd(); 
    return (((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) & 0x7fff); 
} 
+1

ええと、私は知らない、機能はすでにそこにある...それを再実装しようとする理由は? –

+10

@Rocky、私たちが当然のことと考えるコードの基礎を理解しようとすることに何も問題はありません。実際それは励まされるべきです。 –

+0

@Rocky:確かに!あなたが少なくともその原則を説明することができるという希望を持っていなければ、何かを当然としてはいけません。チー・グオ:LCGに疲れたら、人気の高い、高品質のPRNGメルセンヌ・ツイスターをチェックしてください。 –

答えて

18

それだけモジュラ算術です。乗算して2^32を法とする数に加算し、上位16ビットをあなたの「ランダム」数として返します。モジュラスに掛け合う数値を掛け合わせて加算しているので、均等に分布した数々のソートが作成されます。

2つの数字を慎重に選択することは非常に重要です。たとえば、「* 4」と「+ 8」を使用していた場合、多分ランダム性はほとんどありません。

このスキームはlinear congruentialと呼ばれます。

2

Linear Congruential Generator(LCG)やその他の同様のファミリや擬似乱数ジェネレータの説明、およびこの特定の定数の選択については、今月号(7-2011)に掲載された優れた記事Dobb Journal(DDJ):Fast, High-Quality, Parallel Random-Number Generators: Comparing Implementations

私はあなたがこの記事(link)の最初の部分を読むために(無料)DDJのウェブサイトで登録する必要がありますと思いますが、あなたはC++や数学に興味があればあなたはとにかくそれを行う必要があります...

+0

ありがとう:)私は与えられたリンクに入るが、英語は母国語ではないので、読みにくい。私はベストを尽くす。 – moonkey

0

randを呼び出す前に、srandのマニュアルページに "シード値が指定されていない場合、rand()関数は自動的に1"の値でシードされます。 rand()によって返される疑似乱数の新しいシーケンスのシードとしてその引数を設定します。

enter code here 
BEGIN { 
    n0 = "00" 
    srand() 
    n1 = sprintf("%02x", int(255 * rand())) 
    n2 = sprintf("%02x", int(255 * rand())) 
    n3 = sprintf("%02x", int(255 * rand())) 
    n4 = sprintf("%02x", int(255 * rand())) 
    n5 = sprintf("%02x", int(255 * rand())) 
    print n0":"n1":"n2":"n3":"n4":"n5 
} 

:すなわち.genmacaddrコードスニペットで参照 - 例として

、次のawkを考慮し、nawkの、新しい(ランダム)のMACアドレスを作成するために、bashシェルスクリプトで使用されるコードをgawkはbashシェルスクリプトのコードスニペットがどこにあるか:

enter code here 
ifconfig eth0 down 
newmacaddr=`nawk -f .genmacaddr -` 
ifconfig eth0 hw ether $newmacaddr 
ifconfig eth0 up 

私は間違っていないよ場合は、srand関数のシード値は、システムクロックから導出されます。

これは、これがうまくいくコーディングソリューションへのアプローチを理解するのに役立ちます。

0

)シードが(_getptdに格納されて

(あなたはこれらの擬似ランダム値を生成する方法についての深さの解説にしたい場合は、あなたがそれを調べることができます)、それは線形合同だと述べてきたように - > _ holdrand(ホールドランドと呼ばれます)

このコードは、通常の乗算​​と加算のステップを実行してから "holdrand"をオーバーフローさせて に "implulus" 0x100000000を取得します。

これはすぐにはわかりませんが、一般的には良いスタイルとは考えられないため、これについて言及します。

技術的に整数変数をオーバーフローさせると、定義されていない動作が通知されますが、ほとんどのプラットフォームでは、Microsoftのエンジニアがその問題を無視しているため、