random マクロコマンドに大きな値を渡した場合の問題
挙げられているURLはちょっと内容が酷いので、参考にしない方がいいです。
例えば、1~3 の乱数二つを掛けた場合、1, 2, 3, 2, 4, 6, 3, 6, 9 の9パターンとなり、 2, 3, 6が二倍の確率で出現する上に5, 7, 8がまったく出ません。
さらに 0~2 で考えた場合は 0, 0, 0, 0, 1, 2, 0, 2, 4 と半数以上が 0 になります。
このように、より大きな乱数を得ようとして二つの乱数を掛けてしまうと 一様でない値が得られるので、リンク先のページは最初の時点で誤っています。
rand() でやるとしたら、
(((unsigned int)rand()) << 15) | (unsigned int)rand() // 30ビットとか
unsigned int r, r1, r2, r3; r1 = rand(); r2 = rand(); r3 = rand(); r = ((r1 & 0x6000) << 17) | (r2 << 15) | r3; // 32ビットのようなビット演算を使う必要があります。
ただこの方法で大きな乱数を得ても元々のrand()の品質の悪さの影響は受けるので、 それよりはメルセンヌ・ツイスタのソースを持ってきたり、 ttssh でも使っている arc4random() を使う方がいいと思います。
# rand_s()が使えたら楽なのですが、XP以降でした
最初は ChaCha20 ベースの arc4random() を使おうかと思っていたのですが、 新たに OpenSSL をリンクするようにする必要がある為これを避けて、 SFMT を使う方向で検討しています。
すみません。ファイルが添付されているのに今気が付きました。
という事からほぼ macro 専用になりそうだったので、 必要な部分のソースを直接取り込んじゃいました。
ライブラリとして別に分けた方がよかったですか?
TTSSH 側では使わないんですね。それならよいと思います。
インポートすると差し替えづらくなりますし、インポート元が更新されても放置されがちなので、そこに気をつけたいところです。
別ライブラリにするかどうかの判断基準は、おおむねこんな感じかと思います。
現状でインポートしたり、イレギュラーなもの:
RAND_MAX が 0x7FFF(32767) のため、これより細かい粒度の乱数を得ようとしても得られない。
この方法を利用すると 0x7FFF*0x7FFF = 3FFF0001(1073676289) になる。
http://www.lab.its55.com/?p=77