Cでrandom()の状態を保存する。initstate()とsetstate()の使い方。こせきの技術日記スマートフォン用の表示で見るこせきの技術日記この広告は、90日以上更新していないブログに表示しています。2010-05-23Cでrandom()の状態を保存する。initstate()とsetstate()の使い方。srandom(1)で初期化した後、random()を100万回呼んだときの状態を保存したい。pythonだと簡単にできるのだけど、Cだと難しい。マニュアルにinitstate()とsetstate()という関数が載っているが、使い方がさっぱりわからなかった。検索すると「必要な回数ループしろ」なんていうダメ回答しか見つからない。仕方ないので頑張ってソースを読んだ。アルゴリズムはわからないが、何をやってるかは理解できる。状態配列の先頭に、乱数生成器のタイプと状態配列の位置情報がまとめて保存されている。stateは状態配列の2個目の要素を指すポインタ。random()を呼ぶたびに状態配列のポインタが動くが、state[-1]が更新されるわけではない。sate[-1]が更新されるタイミングは、initstate()か、setstate()を呼んだ時。initstate()は内部でsrandom()を呼んでしまう。状態を保存したいだけなのに、初期化する意味がない。setstate()を呼ぶと、戻り値のstate[-1]が更新される。要するに、setstateの戻り値が保存可能な状態配列。ここでrandom()を必要なだけ呼ぶ。状態配列stateを更新。ここでstateを保存する。ポインタを使った方がわかりやすいかもしれない。ここでrandom()を必要なだけ呼ぶ。stateを更新・待避。ここでstateを保存する。dummyからstateに戻す。してもうまくいかない。ここでrandom()を必要なだけ呼ぶ。これ以降、setstate(state)のせいでrandom()の値が変わってしまう。一回setstate()すれば復旧するが、これでは意味がわからなすぎる。ソースのコメントには使用中のstateをsetstateに渡しても大丈夫と書いてあるが、少なくとも手元のOSXではうまくいかなかった。setstate()の冒頭部分を見るとダメな理由がわかる。更新前の状態配列で内部状態を上書きしている。ここで引数で渡された(未更新の)位置が取り込まれてしまう。戻り値のstate[-1]が更新される。stateを入れ替え。上で取り込んだ未更新の位置が内部状態rptrに設定されてしまった。戻り値はOKだが、内部状態が正しくない。