List of Mersenne-Twister - text.Baldanders.info
tag:text.Baldanders.info,2024-03-09:/tags
2024-03-09T20:45:42+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
github.com/goark/mt/v2 をリリースした
tag:text.Baldanders.info,2024-03-09:/release/2024/03/goark-mt-v2/
2024-03-09T11:45:42+00:00
2024-03-09T11:45:46+00:00
Mersenne Twister 疑似乱数生成器を実装した拙作のパッケージを math/rand/v2 に対応することにした
Spiegel
https://baldanders.info/profile/
<p><a href="https://go.dev/">Go</a> 1.22 で <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>math/rand/v2</code></a> パッケージが登場したため, <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> 疑似乱数生成器を実装した拙作の <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt</code></a> パッケージも <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>math/rand/v2</code></a> に対応することにした。</p>
<p>まずはバージョンを v2 に上げて,以下のインポート・パスに変更した。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">"github.com/goark/mt/v2"</span>
</span></span></code></pre></div><p>また <code>go.mod</code> も同様に</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">require github.com/goark/mt/v2 v2.0.1
</span></span></code></pre></div><p>とする。</p>
<p>例として <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a> パッケージと <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>math/rand/v2</code></a> パッケージを組み合わせて標準正規分布する値を1万個生成してみる。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand/v2"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">Int64</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">points</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">float64</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">max</span> <span class="o">:=</span> <span class="mf">0.0</span>
</span></span><span class="line"><span class="cl"> <span class="nx">min</span> <span class="o">:=</span> <span class="mf">1.0</span>
</span></span><span class="line"><span class="cl"> <span class="nx">sum</span> <span class="o">:=</span> <span class="mf">0.0</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="k">range</span> <span class="mi">10000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">point</span> <span class="o">:=</span> <span class="nx">rnd</span><span class="p">.</span><span class="nf">NormFloat64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">points</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">points</span><span class="p">,</span> <span class="nx">point</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">min</span> <span class="p">=</span> <span class="nx">math</span><span class="p">.</span><span class="nf">Min</span><span class="p">(</span><span class="nx">min</span><span class="p">,</span> <span class="nx">point</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">max</span> <span class="p">=</span> <span class="nx">math</span><span class="p">.</span><span class="nf">Max</span><span class="p">(</span><span class="nx">max</span><span class="p">,</span> <span class="nx">point</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">sum</span> <span class="o">+=</span> <span class="nx">point</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">n</span> <span class="o">:=</span> <span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">points</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ave</span> <span class="o">:=</span> <span class="nx">sum</span> <span class="o">/</span> <span class="nx">n</span>
</span></span><span class="line"><span class="cl"> <span class="nx">d2</span> <span class="o">:=</span> <span class="mf">0.0</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">p</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">points</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">d2</span> <span class="o">+=</span> <span class="p">(</span><span class="nx">p</span> <span class="o">-</span> <span class="nx">ave</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="nx">p</span> <span class="o">-</span> <span class="nx">ave</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">" minimum: "</span><span class="p">,</span> <span class="nx">min</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">" maximum: "</span><span class="p">,</span> <span class="nx">max</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">" average: "</span><span class="p">,</span> <span class="nx">ave</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"standard deviation: "</span><span class="p">,</span> <span class="nx">math</span><span class="p">.</span><span class="nf">Sqrt</span><span class="p">(</span><span class="nx">d2</span><span class="o">/</span><span class="nx">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これを実行するとこんな感じになる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample.go
</span></span><span class="line"><span class="cl"> minimum: -4.465497509270884
</span></span><span class="line"><span class="cl"> maximum: 4.409945906326592
</span></span><span class="line"><span class="cl"> average: 0.010399867661332784
</span></span><span class="line"><span class="cl">standard deviation: 1.0027323703801945
</span></span></code></pre></div><p>まぁまぁ妥当な感じ?</p>
<p><a href="https://pkg.go.dev/math/rand" title="rand package - math/rand - Go Packages"><code>math/rand</code></a> および <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>math/rand/v2</code></a> パッケージのトップレベル関数群の疑似乱数生成器が ChaCha8 になったおかげで seed を与えるのがめっちゃ楽になった。
これだけでもありがたい。
ともかくこれで,乱数生成周りの調査と対応は一通り完了かな。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/release/mersenne-twister-by-golang/">疑似乱数生成器 goark/mt</a></li>
<li><a href="https://text.baldanders.info/golang/pseudo-random-number-generator-v2/">Go 1.22 における疑似乱数生成器</a></li>
<li><a href="https://zenn.dev/spiegel/articles/20240309-golang-math-rand-v2">Go 1.22 の math/rand/v2 を使ってみる</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B0CFL1DK8Q?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51BmDUG6D0L._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B0CFL1DK8Q?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語 100Tips ありがちなミスを把握し、実装を最適化する impress top gearシリーズ</a></dt>
<dd>Teiva Harsanyi (著), 柴田 芳樹 (著)</dd>
<dd>インプレス 2023-08-18 (Release 2023-08-18)</dd>
<dd>Kindle版</dd>
<dd>B0CFL1DK8Q (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://book.impress.co.jp/books/1122101133">版元</a>で PDF 版を購入可能。事実上の Effective Go とも言える充実の内容。オリジナルは敢えてタイトルに “tips” という単語を入れるのを避けたのに邦題が「100 Tips」とかなっていて,原作者がお怒りとの噂(あくまで噂)</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2023-08-18">2023-08-18</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語 100Tips -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4814400535?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41+ew2wl2jL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4814400535?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">効率的なGo ―データ指向によるGoアプリケーションの性能最適化</a></dt>
<dd>Bartłomiej Płotka (著), 山口 能迪 (翻訳)</dd>
<dd>オライリー・ジャパン 2024-02-24</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4814400535 (ASIN), 9784814400539 (EAN), 4814400535 (ISBN)</dd>
</dl>
<p class="description">ついに Effective Go のタイトルを冠した本の邦訳が出た。<a href="https://www.oreilly.co.jp/books/9784814400539/">版元</a>で Ebook を買える。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2024-02-22">2024-02-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 効率的なGo : Effective Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B015643CPE?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51t6yHHVwEL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B015643CPE?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">暗号技術入門 第3版 秘密の国のアリス</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2015-08-25 (Release 2015-09-17)</dd>
<dd>Kindle版</dd>
<dd>B015643CPE (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">SHA-3 や Bitcoin/Blockchain など新しい知見や技術要素を大幅追加。暗号技術を使うだけならこれ1冊でとりあえず無問題。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2015-09-20">2015-09-20</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 暗号技術入門 第3版 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1FO?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41353H+BzFL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1FO?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガール/乱択アルゴリズム</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2011-02-25 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1FO (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">工学ガール,リサちゃん登場!</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2015-04-19">2015-04-19</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 数学ガール/乱択アルゴリズム -->
疑似乱数生成器 goark/mt
tag:text.Baldanders.info,2019-09-22:/release/mersenne-twister-by-golang/
2019-09-22T08:37:19+00:00
2024-03-09T11:45:46+00:00
goark/mt は64bit版 Mersenne Twister を元に pure Go で書き直したものである。
Spiegel
https://baldanders.info/profile/
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> とは<a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/" title="Makoto Matsumoto Home Page">松本眞</a>・西村拓士両氏によって1996年に発表された擬似乱数生成アルゴリズムである。
他の擬似乱数生成アルゴリズムと比べて以下の特徴があるそうだ。</p>
<figure>
<blockquote><ul>
<li>従来の様々な生成法の欠点を考慮して設計されています</li>
<li>従来にない長周期, 高次元均等分布を持ちます(周期が $2^{19937}-1$ で、623次元超立方体の中に 均等に分布することが証明されています)</li>
<li>生成速度がかなり速い</li>
<li>メモリ効率が良い</li>
</ul>
</blockquote>
<figcaption><div><q><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/what-is-mt.html">Mersenne Twister とは?</a></q>より</div></figcaption>
</figure>
<p>特に2番目が重要で,モンテカルロ法などの科学技術計算に向いている。
Ruby などの一部のプログラミング言語では標準の疑似乱数生成器として組み込まれているらしい。</p>
<p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a> パッケージは <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> のオリジナルコード(C/C++)を pure <a href="https://go.dev/">Go</a> で書き直したものである。</p>
<p><a href="https://github.com/goark/mt/actions"><img src="https://github.com/goark/mt/workflows/vulns/badge.svg" alt="check vulns"></a>
<a href="https://github.com/goark/mt/actions"><img src="https://github.com/goark/mt/workflows/lint/badge.svg" alt="lint status"></a>
<a href="https://raw.githubusercontent.com/goark/mt/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="GitHub license"></a>
<a href="https://github.com/goark/mt/releases/latest"><img src="https://img.shields.io/github/release/goark/mt.svg" alt="GitHub release"></a></p>
<p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a> パッケージの特徴は以下の通り。</p>
<ul>
<li><a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>math/rand/v2</code></a> パッケージ互換で <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>rand</code></a><code>.Rand</code> のソースとして利用できる</li>
<li>並行的に安全(concurrency safe)な構成にできる(<a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.PRNG</code> 型を利用した場合)</li>
</ul>
<h2>github.com/goark/mt/v2/mt19937.Source の機能</h2>
<p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a><code>/mt19937</code> パッケージは <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt64.html">64bit版 Mersenne Twister</a> を元に pure <a href="https://go.dev/">Go</a> で書き直したものである。</p>
<p><code>mt19937.Source</code> はそのまま疑似乱数生成器として使える。
たとえば以下のように記述する。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">mt</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="mi">19650218</span><span class="p">)).</span><span class="nf">Uint64</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//Output:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">//13735441942630277712
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>提供するメソッドは以下の通り。</p>
<table>
<thead>
<tr>
<th>メソッド</th>
<th>機能</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Source.Seed(int64)</code></td>
<td>乱数のシードをセットする</td>
</tr>
<tr>
<td><code>Source.SeedArray([]uint64)</code></td>
<td>乱数のシード(配列)をセットする</td>
</tr>
<tr>
<td><code>Source.Uint64() uint64</code></td>
<td>乱数として範囲 $[0, 2^{64}-1]$ の整数値を生成する</td>
</tr>
<tr>
<td><code>Source.Real(int) float64</code></td>
<td>乱数として浮動小数点数値を生成する</td>
</tr>
</tbody>
</table>
<p><code>Source.Real()</code> 関数の引数による乱数の出力範囲は以下の通り。</p>
<table>
<thead>
<tr>
<th style="text-align:center">引数</th>
<th>生成範囲</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">1</td>
<td>範囲 $[0, 1)$ の浮動小数点数値</td>
</tr>
<tr>
<td style="text-align:center">2</td>
<td>範囲 $(0, 1)$ の浮動小数点数値</td>
</tr>
<tr>
<td style="text-align:center">上記以外</td>
<td>範囲 $[0, 1]$ の浮動小数点数値</td>
</tr>
</tbody>
</table>
<p>なお <code>mt19937.Source</code> は並行的に安全ではないので goroutine 間でインスタンスを共有できない。</p>
<h2>math/rand/v2 パッケージと組み合わせる</h2>
<p><code>mt19937.Source</code> を <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>math/rand/v2</code></a> パッケージの <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>rand</code></a><code>.Rand</code> のソースとして利用するには以下のように記述すればよい。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand/v2"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="mi">19650218</span><span class="p">)).</span><span class="nf">Uint64</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//Output:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">//13735441942630277712
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>これで <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>rand</code></a><code>.Rand</code> が提供するメソッドはすべて使える。
ただし <a href="https://pkg.go.dev/math/rand/v2" title="rand package - math/rand - pkg.go.dev"><code>rand</code></a><code>.Rand</code> 自体も並行的に安全ではないので,取り扱いにはやはり注意が必要である。</p>
<h2>mt.PRNG と組み合わせる</h2>
<p><code>mt19937.Source</code> 型を <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.PRNG</code> 型と組み合わせることで並行的に安全な構成にできる。
たとえばこんな感じに記述できる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand/v2"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">start</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span> <span class="o">:=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prng</span> <span class="o">:=</span> <span class="nx">mt</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">Int64</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="mi">1000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="mi">10000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prng</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Time:"</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">start</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.PRNG</code> 型は <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a><code>/mt19937.Source</code> のラッパーになっている。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand/v2"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Source represents a source of uniformly-distributed
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">Source</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rand</span><span class="p">.</span><span class="nx">Source</span>
</span></span><span class="line"><span class="cl"> <span class="nf">SeedArray</span><span class="p">([]</span><span class="kt">uint64</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Real</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="kt">float64</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// PRNG is class of pseudo random number generator.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">PRNG</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">source</span> <span class="nx">Source</span>
</span></span><span class="line"><span class="cl"> <span class="nx">mutex</span> <span class="o">*</span><span class="nx">sync</span><span class="p">.</span><span class="nx">Mutex</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3>io.Reader 互換の疑似乱数生成器</h3>
<p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.PRNG</code> のインスタンスから <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.Reader</code> 型のインスタンスを生成できる。
こんな感じに記述できる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"encoding/binary"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand/v2"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/mt/v2/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span> <span class="o">:=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prng</span> <span class="o">:=</span> <span class="nx">mt</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">Int64</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="mi">1000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">r</span> <span class="o">:=</span> <span class="nx">prng</span><span class="p">.</span><span class="nf">NewReader</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">buf</span> <span class="o">:=</span> <span class="p">[</span><span class="mi">8</span><span class="p">]</span><span class="kt">byte</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="mi">10000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ct</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">r</span><span class="p">.</span><span class="nf">Read</span><span class="p">(</span><span class="nx">buf</span><span class="p">[:])</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">binary</span><span class="p">.</span><span class="nx">LittleEndian</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">(</span><span class="nx">buf</span><span class="p">[:</span><span class="nx">ct</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.Reader</code> 型は <a href="https://golang.org/pkg/io/" title="io - The Go Programming Language"><code>io</code></a><code>.Reader</code> インタフェースと互換性がある。
また <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.Reader</code> インスタンスも並行的に安全なので goroutine 間で共有可能である。</p>
<h2>ライセンスについて</h2>
<p><a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a> パッケージは MIT ライセンスで提供している。</p>
<p>オリジナルの <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> コードは GPL または BSD ライセンスで提供されているが MIT ライセンスに書き換えてもいいらしい。</p>
<ul>
<li><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/license.html">Mersenne Twisterの商業利用について</a></li>
</ul>
<p>というわけで <a href="https://github.com/goark/mt" title="goark/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>github.com/goark/mt/v2</code></a> パッケージは MIT ライセンスで提供することにした。
ご利用はお気軽に。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1FO?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41353H+BzFL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1FO?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガール/乱択アルゴリズム</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2011-02-25 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1FO (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">工学ガール,リサちゃん登場!</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2015-04-19">2015-04-19</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 数学ガール/乱択アルゴリズム -->
疑似乱数生成器 spiegel-im-spiegel/mt をリリースした
tag:text.Baldanders.info,2019-09-22:/release/2019/09/mersenne-twister-package-is-released/
2019-09-22T08:37:19+00:00
2024-03-09T11:45:46+00:00
ついカッとなって書いた。反省はしていない。
Spiegel
https://baldanders.info/profile/
<p>ついカッとなって書いた。
反省はしていない。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/mt">spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang</a></li>
</ul>
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> の <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>実装はいくつかあるのだが,やっぱ他人が作る道具は使いにくいよね,というわけで自分で書いてしまった(笑)
<a href="https://github.com/spiegel-im-spiegel/mt" title="spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang">spiegel-im-spiegel/mt</a> の特徴は以下の通り。</p>
<ul>
<li><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> 互換で <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> のソースとして利用できる</li>
<li>goroutine-safe な構成にできる(<a href="https://github.com/spiegel-im-spiegel/mt" title="spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.PRNG</code> 型を利用した場合)</li>
</ul>
<p>使い方は以下を参照のこと。</p>
<ul>
<li><a href="https://text.baldanders.info/release/mersenne-twister-by-golang/">疑似乱数生成器 spiegel-im-spiegel/mt</a></li>
</ul>
<p>一応,ベンチマークテストもしてみた。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"testing"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spiegel-im-spiegel/mt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/spiegel-im-spiegel/mt/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="nx">count</span> <span class="p">=</span> <span class="mi">10000000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">BenchmarkRandomALFG</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">B</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()).(</span><span class="nx">rand</span><span class="p">.</span><span class="nx">Source64</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span><span class="p">.</span><span class="nf">ResetTimer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">count</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">BenchmarkRandomMT19917</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">B</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">mt19937</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span><span class="p">.</span><span class="nf">ResetTimer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">count</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">BenchmarkRandomALFGRand</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">B</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span><span class="p">.</span><span class="nf">ResetTimer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">count</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">BenchmarkRandomMT19917Rand</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">B</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span><span class="p">.</span><span class="nf">ResetTimer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">count</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">BenchmarkRandomALFGLocked</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">B</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span><span class="p">.</span><span class="nf">ResetTimer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">count</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rand</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">BenchmarkRandomMT19917Locked</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">B</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span> <span class="o">:=</span> <span class="nx">mt</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">mt19937</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">UnixNano</span><span class="p">()))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span><span class="p">.</span><span class="nf">ResetTimer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nx">count</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rnd</span><span class="p">.</span><span class="nf">Uint64</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>テスト対象は以下の通り。</p>
<table>
<thead>
<tr>
<th>テスト名</th>
<th>対象</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>BenchmarkRandomALFG</code></td>
<td><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> 標準アルゴリズム<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></td>
</tr>
<tr>
<td><code>BenchmarkRandomMT19917</code></td>
<td><a href="https://github.com/spiegel-im-spiegel/mt" title="spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>/mt19937</code> パッケージ</td>
</tr>
<tr>
<td><code>BenchmarkRandomALFGRand</code></td>
<td><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> (<a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> ラッパ)</td>
</tr>
<tr>
<td><code>BenchmarkRandomMT19917Rand</code></td>
<td><a href="https://github.com/spiegel-im-spiegel/mt" title="spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>/mt19937</code> (<a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>rand</code></a><code>.Rand</code> ラッパ)</td>
</tr>
<tr>
<td><code>BenchmarkRandomALFGLocked</code></td>
<td><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> Sync バージョン</td>
</tr>
<tr>
<td><code>BenchmarkRandomMT19917Locked</code></td>
<td><a href="https://github.com/spiegel-im-spiegel/mt" title="spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>/mt19937</code> + <a href="https://github.com/spiegel-im-spiegel/mt" title="spiegel-im-spiegel/mt: Mersenne Twister; Pseudo Random Number Generator, Implemented by Golang"><code>mt</code></a><code>.PRNG</code></td>
</tr>
</tbody>
</table>
<p>このベンチマークテストの実行結果は以下の通り。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go test -bench Random -benchmem
</span></span><span class="line"><span class="cl">goos: linux
</span></span><span class="line"><span class="cl">goarch: amd64
</span></span><span class="line"><span class="cl">pkg: github.com/spiegel-im-spiegel/mt/benchmark
</span></span><span class="line"><span class="cl">BenchmarkRandomALFG-4 1000000000 0.0492 ns/op 0 B/op 0 allocs/op
</span></span><span class="line"><span class="cl">BenchmarkRandomMT19917-4 1000000000 0.0651 ns/op 0 B/op 0 allocs/op
</span></span><span class="line"><span class="cl">BenchmarkRandomALFGRand-4 1000000000 0.0749 ns/op 0 B/op 0 allocs/op
</span></span><span class="line"><span class="cl">BenchmarkRandomMT19917Rand-4 1000000000 0.0846 ns/op 0 B/op 0 allocs/op
</span></span><span class="line"><span class="cl">BenchmarkRandomALFGLocked-4 1000000000 0.176 ns/op 0 B/op 0 allocs/op
</span></span><span class="line"><span class="cl">BenchmarkRandomMT19917Locked-4 1000000000 0.192 ns/op 0 B/op 0 allocs/op
</span></span><span class="line"><span class="cl">PASS
</span></span><span class="line"><span class="cl">ok github.com/spiegel-im-spiegel/mt/benchmark 7.081s
</span></span></code></pre></div><p>というわけで <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> のほうが若干速いかな。
乱数としての性能は別の機会に。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1FO?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41353H+BzFL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1FO?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガール/乱択アルゴリズム</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2011-02-25 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1FO (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">工学ガール,リサちゃん登場!</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2015-04-19">2015-04-19</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 数学ガール/乱択アルゴリズム -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language">math/rand</a> パッケージに実装されている擬似乱数生成器は<a href="https://groups.google.com/forum/#!topic/golang-nuts/RZ1G3_cxMcM">ラグ付フィボナッチ法(Lagged Fibonacci Generator)のバリエーション</a>らしい。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
モンテカルロ法による円周率の推定(その4 PRNG)
tag:text.Baldanders.info,2016-11-20:/golang/estimate-of-pi-4-prng/
2016-11-20T14:33:55+00:00
2024-03-09T11:45:46+00:00
math/rand パッケージでは rand.Source interface を持つ別の擬似乱数生成器を使うことができる。
Spiegel
https://baldanders.info/profile/
<ol>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi/">モンテカルロ法による円周率の推定(その1)</a></li>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi-2-cli/">モンテカルロ法による円周率の推定(その2 CLI)</a></li>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi-3-gaussian/">モンテカルロ法による円周率の推定(その3 Gaussian)</a></li>
<li><a href="https://text.baldanders.info/golang/estimate-of-pi-4-prng/">モンテカルロ法による円周率の推定(その4 PRNG)</a> ← イマココ</li>
</ol>
<p>「モンテカルロ法による円周率の推定」もひととおり終わったので,今回は擬似乱数生成器(pseudo random number generator)の話。</p>
<h2>math/rand の擬似乱数生成器</h2>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>では <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>math/rand</code></a> パッケージで擬似乱数を取り扱えることは「<a href="https://text.baldanders.info/golang/estimate-of-pi/" title="モンテカルロ法による円周率の推定(その1)">その1</a>」で紹介した通り。
<a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>math/rand</code></a> パッケージに実装されている擬似乱数生成器はラグ付フィボナッチ法(Lagged Fibonacci Generator)のバリエーションらしい。</p>
<figure lang="en">
<blockquote>
<q>If I am not mistaken again, the generator is an ALFG (Additive Lagged Fibonacci Generator, thats what Wikipedia calls it). Knuth describes the algorithm in Volume 2 of The art of computer programming in section 3.2.2 (around equation 7). Both Wikipedia and Knuth state the parameter combination 607,273 as possible combination with a period length of 2^(e-1) * (2^607-1) where e is the length of the random number in bits.<br>
I actually found a few references examining its properties and it seems to be a good rng so faar, but there is still seems to be a lack of mathematical background and it is fairly easy to get into trouble by not seeding properly.</q>
</blockquote>
<figcaption><div>via <q><a href="https://groups.google.com/forum/#!topic/golang-nuts/RZ1G3_cxMcM">[Announce] A rand package for high quality 64bit random numbers (possibly go2)</a></q></div></figcaption>
</figure>
<p>ラグ付フィボナッチ法は<a href="#lcg">線形合同法(後述)</a>を改善することを目的としたものでフィボナッチ数の生成法を元にしている。</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Lagged_Fibonacci_generator">Lagged Fibonacci generator - Wikipedia</a></li>
</ul>
<p>ラグ付フィボナッチ法は以下の式で表される。</p>
<figure>
<blockquote>
\begin{alignat*}{2}
S_{n} \equiv S_{n-j} * S_{n-k} \pmod{m}, & \; & 0 \lt j \lt k
\end{alignat*}
</blockquote></figure>
<p>ラグ付フィボナッチ法は $ * $ 演算子によってバリエーションがあるが <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>math/rand</code></a> パッケージの実装では加算を使うため “<strong>Additive</strong> Lagged Fibonacci Generator” ということらしい。
ソースコードで言うとこの部分かな。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="p">(</span><span class="nx">rng</span> <span class="o">*</span><span class="nx">rngSource</span><span class="p">)</span> <span class="nf">Int63</span><span class="p">()</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rng</span><span class="p">.</span><span class="nx">tap</span><span class="o">--</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">rng</span><span class="p">.</span><span class="nx">tap</span> <span class="p"><</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rng</span><span class="p">.</span><span class="nx">tap</span> <span class="o">+=</span> <span class="nx">_LEN</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">rng</span><span class="p">.</span><span class="nx">feed</span><span class="o">--</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">rng</span><span class="p">.</span><span class="nx">feed</span> <span class="p"><</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rng</span><span class="p">.</span><span class="nx">feed</span> <span class="o">+=</span> <span class="nx">_LEN</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="p">(</span><span class="nx">rng</span><span class="p">.</span><span class="nx">vec</span><span class="p">[</span><span class="nx">rng</span><span class="p">.</span><span class="nx">feed</span><span class="p">]</span> <span class="o">+</span> <span class="nx">rng</span><span class="p">.</span><span class="nx">vec</span><span class="p">[</span><span class="nx">rng</span><span class="p">.</span><span class="nx">tap</span><span class="p">])</span> <span class="o">&</span> <span class="nx">_MASK</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rng</span><span class="p">.</span><span class="nx">vec</span><span class="p">[</span><span class="nx">rng</span><span class="p">.</span><span class="nx">feed</span><span class="p">]</span> <span class="p">=</span> <span class="nx">x</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">x</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2>擬似乱数生成器のバリエーション</h2>
<p><a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>math/rand</code></a> パッケージでは以下の <a href="https://golang.org/doc/effective_go.html#interfaces_and_types" title="Effective Go - The Go Programming Language">interface</a> を持つ別の擬似乱数生成器を使うことができる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// A Source represents a source of uniformly-distributed
</span></span></span><span class="line"><span class="cl"><span class="c1">// pseudo-random int64 values in the range [0, 1<<63).
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">Source</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Int63</span><span class="p">()</span> <span class="kt">int64</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Seed</span><span class="p">(</span><span class="nx">seed</span> <span class="kt">int64</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>以下に2つほど紹介する。</p>
<h3 id="lcg">線形合同法</h3>
<p>線形合同法(Linear Congruential Generator)は昔の擬似乱数ライブラリでよく使われていたアルゴリズムで,以下の式で表される。</p>
<figure>
<blockquote>
\[
X_{n+1} = (A \times X_{n} + B) \bmod M
\]
</blockquote></figure>
<p>定数 $A$ および $B$ の与え方により幾つかバリエーションがある。</p>
<p>線形合同法のメリットは実装サイズが小さく計算量も少ない点だろうか。
一方デメリットとしては,多次元で疎に分布する性質があり,周期も小さいため乱数を大量に発生させる必要がある科学技術シミュレーションなどには向かないと言われている。
このためメモリサイズが限られるマイクロ・コントローラのようなものでもない限り線形合同法が使われることはなくなった。</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>でわざわざ線形合同法を実装しているパッケージは少ないのだが,たとえば以下のパッケージがある<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
<ul>
<li><a href="https://github.com/davidminor/gorand">davidminor/gorand: Basic golang implementation of a permuted congruential generator for pseudorandom number generation</a></li>
</ul>
<h3 id="mt">Mersenne Twister</h3>
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> とは<a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/" title="Makoto Matsumoto Home Page">松本眞</a>・西村拓士両氏によって1996年に発表された擬似乱数生成アルゴリズムである。
他の擬似乱数生成アルゴリズムと比べて以下の特徴があるそうだ。
(「<a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/what-is-mt.html" title="What & how is MT?">Mersenne Twister とは?</a>」より)</p>
<ul>
<li>従来の様々な生成法の欠点を考慮して設計されています。</li>
<li>従来にない長周期,高次元均等分布を持ちます。(周期が $2^{19937}-1$ で<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>、623次元超立方体の中に 均等に分布することが証明されています。)</li>
<li>生成速度がかなり速い。(処理系にもよりますが、パイプライン処理やキャッシュメモリ のあるシステムでは、Cの標準ライブラリの <code>rand()</code> より高速なこと もあります。なお、開発当時には cokus 版は <code>rand()</code> より4倍程度高速でしたが、その後 ANSI-C の <code>rand()</code> が LCG 法から lagged-fibonacci に 変更されたこともあり、2002年現在 rand と MT の速度差はあまりありません。)</li>
<li>メモリ効率が良い。(32ビット以上のマシン用に設計された <code>mt19937.c</code> は、 624ワードのワーキングメモリを消費するだけです。 1ワードは32ビット長とします。</li>
</ul>
<p>ちなみに <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> の<a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/license.html" title="Mersenne Twisterの商用について">オリジナル・コードは BSD ライセンスで提供</a>されている。</p>
<p><a href="https://github.com/MersenneTwister-Lab" title="MersenneTwister-Lab">公式のリポジトリ</a>には C/C++ による実装のみのようだが, <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>で実装している人もいるようである。</p>
<ul>
<li><a href="https://github.com/seehuhn/mt19937">seehuhn/mt19937: An implementation of Takuji Nishimura’s and Makoto Matsumoto’s Mersenne Twister pseudo random number generator in Go.</a></li>
<li><a href="https://github.com/nutterts/randgen">nutterts/randgen: Pseudo Random Number Generators implementing the Go(lang) math/rand.Source Interface</a></li>
<li><a href="https://github.com/farces/mt19937_64">farces/mt19937_64: Mersenne Twister (int64) for Go</a></li>
<li><a href="https://github.com/cuixin/goalg">cuixin/goalg: golang algorithms</a></li>
<li><a href="https://github.com/cpmech/gosl">cpmech/gosl: Go scientific library</a> : <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/" title="SIMD-oriented Fast Mersenne Twister">SFMT</a> や <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/" title="Tiny Mersenne Twister">TinyMT</a> に対応。オリジナルのコードを <a href="https://golang.org/cmd/cgo/" title="cgo - The Go Programming Language">cgo</a> で結合しているのでクロス環境では注意</li>
</ul>
<h2>擬似乱数生成器を組み込む</h2>
<p>では,先ほど紹介した擬似乱数生成器を今回のコードに組み込んでみることにしよう。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">gencmplx</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/rand"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/davidminor/gorand/lcg"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/seehuhn/mt19937"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//RNGs is kind of RNG
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">RNGs</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="nx">NULL</span> <span class="nx">RNGs</span> <span class="p">=</span> <span class="kc">iota</span>
</span></span><span class="line"><span class="cl"> <span class="nx">GO</span>
</span></span><span class="line"><span class="cl"> <span class="nx">LCG</span>
</span></span><span class="line"><span class="cl"> <span class="nx">MT</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//NewRndSource returns Source of random numbers
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">NewRndSource</span><span class="p">(</span><span class="nx">rng</span> <span class="nx">RNGs</span><span class="p">,</span> <span class="nx">seed</span> <span class="kt">int64</span><span class="p">)</span> <span class="nx">rand</span><span class="p">.</span><span class="nx">Source</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="nx">rng</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">LCG</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">lcg</span><span class="p">.</span><span class="nf">NewLcg64</span><span class="p">(</span><span class="nb">uint64</span><span class="p">(</span><span class="nx">seed</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">MT</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nx">mt</span> <span class="o">:=</span> <span class="nx">mt19937</span><span class="p">.</span><span class="nf">New</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">mt</span><span class="p">.</span><span class="nf">Seed</span><span class="p">(</span><span class="nx">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">mt</span>
</span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">rand</span><span class="p">.</span><span class="nf">NewSource</span><span class="p">(</span><span class="nx">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>gencmplx.NewRndSource()</code> 関数で <code>rand.Source</code> オブジェクトを生成する<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>。
これを「<a href="https://text.baldanders.info/golang/estimate-of-pi/" title="モンテカルロ法による円周率の推定(その1)">その1</a>」で作った <code>gencmplx.New()</code> 関数に渡せばよい。</p>
<p>CLI は以下のように調整してみた。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run main.go estmt --help
</span></span><span class="line"><span class="cl">Estimate of Pi with Monte Carlo method.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Usage:
</span></span><span class="line"><span class="cl"> pi estmt [flags]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Flags:
</span></span><span class="line"><span class="cl"> -e, --ecount int Count of estimate (default 100)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Global Flags:
</span></span><span class="line"><span class="cl"> -p, --pcount int Count of points (default 10000)
</span></span><span class="line"><span class="cl"> -r, --rsource string Source of RNG (GO/LCG/MT) (default "GO")
</span></span></code></pre></div><p>で,それぞれの擬似乱数生成器で評価を行ってみようと思ったのだが,今回のケースに限ってはあまり違いが出ないようである。</p>
<p>まずは<a href="#lcg">線形合同法</a>の場合。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run main.go estmt -e 10000 -p 100000 -r LCG > estmt100k-lcg.dat
</span></span><span class="line"><span class="cl">random number generator: LCG
</span></span><span class="line"><span class="cl">minimum value: 3.12204
</span></span><span class="line"><span class="cl">maximum value: 3.16224
</span></span><span class="line"><span class="cl">average value: 3.14164
</span></span><span class="line"><span class="cl">standard deviation: 0.00524 (68.3%)
</span></span></code></pre></div><figure style='margin:0 auto;text-align:center;'><a href="./histogram-lcg.png"><img src="./histogram-lcg.png" srcset="./histogram-lcg.png 611w" sizes="(min-width:600px) 500px, 80vw" alt="" loading="lazy"></a></figure>
<figure style='margin:0 auto;text-align:center;'><a href="./qq100k-plot-lcg.png"><img src="./qq100k-plot-lcg.png" srcset="./qq100k-plot-lcg.png 611w" sizes="(min-width:600px) 500px, 80vw" alt="" loading="lazy"></a></figure>
<p>次は <a href="#mt">Mersenne Twister</a> の場合。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run main.go estmt -e 10000 -p 100000 -r MT > estmt100k-mt.dat
</span></span><span class="line"><span class="cl">random number generator: MT
</span></span><span class="line"><span class="cl">minimum value: 3.12380
</span></span><span class="line"><span class="cl">maximum value: 3.16140
</span></span><span class="line"><span class="cl">average value: 3.14165
</span></span><span class="line"><span class="cl">standard deviation: 0.00517 (67.8%)
</span></span></code></pre></div><figure style='margin:0 auto;text-align:center;'><a href="./histogram-mt.png"><img src="./histogram-mt.png" srcset="./histogram-mt.png 611w" sizes="(min-width:600px) 500px, 80vw" alt="" loading="lazy"></a></figure>
<figure style='margin:0 auto;text-align:center;'><a href="./qq100k-plot-mt.png"><img src="./qq100k-plot-mt.png" srcset="./qq100k-plot-mt.png 611w" sizes="(min-width:600px) 500px, 80vw" alt="" loading="lazy"></a></figure>
<p>もっと多次元だったりすると変わってくるのかなぁ。</p>
<h2>暗号技術用途の乱数生成器</h2>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>では暗号技術用途の乱数として <a href="https://golang.org/pkg/crypto/rand/" title="rand - The Go Programming Language"><code>crypto/rand</code></a> パッケージが用意されている。
これは <a href="https://golang.org/pkg/math/rand/" title="rand - The Go Programming Language"><code>math/rand</code></a> とは互換性がない。</p>
<p>具体的には,UNIX 系のプラットフォームでは乱数生成に <code>/dev/urandom</code> デバイスを参照している<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>。
また Windows プラットフォームでは <a href="https://technet.microsoft.com/ja-jp/library/cc734124.aspx">CryptoAPI 2.0</a> の <a href="https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa379942.aspx" title="CryptGenRandom function"><code>CryptGenRandom</code></a> 関数を使っている<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>。</p>
<p>そもそも暗号技術用途の乱数生成器は科学技術シミュレーションやゲームで使う擬似乱数生成器とは要件が異なる。</p>
<ul>
<li><a href="https://tools.ietf.org/html/rfc4086">RFC 4086 - Randomness Requirements for Security</a> (<a href="https://www.ipa.go.jp/security/rfc/RFC4086JA.html" title="セキュリティのための乱雑性についての要件">IPA による日本語訳</a>)</li>
<li><span><a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">NIST Special Publication 800-90A Revision 1: Recommendation for Random Number Generation Using Deterministic Random Bit Generators <sup><i class="far fa-file-pdf"></i></sup></a></span></li>
</ul>
<figure>
<blockquote>
<q>従前の観点から統計的にテストされた乱雑性は、セキュリティ用途に要求される予測困難性と同等では<strong>ありません</strong>。<br>
例えば、(CRC Standard Mathematical Tables からのランダムテーブルのような)広く利用可能な一定のシーケンスの利用は、攻撃者に対して非常に弱いです。これを学習したり、推測する攻撃者は、容易に(過去・未来を問わず)そのシーケンス [CRC] に基づいて、すべてのセキュリティを破ることができます。他の例として、AES を 1, 2, 3 ... のような連続した整数を暗号化する一定の鍵と共に使うことは、優れた統計的乱雑性をもつが予測可能な出力を作り出します。他方、6 面のサイコロを連続して転がして、その結果の値を ASCII にエンコードすることは、実質的に予測困難なコンポーネントをもちながらも「統計的に貧弱な出力」を作り出します。それゆえ、「統計的テストの合否は、『何かが予測不可能であるか否か、あるいは、予測可能であるか否か』を表さないこと」に注意してください。</q>
</blockquote>
<figcaption><div><q><a href="https://www.ipa.go.jp/security/rfc/RFC4086JA.html">RFC 4086 - セキュリティのための乱雑性についての要件</a></q>より</div></figcaption>
</figure>
<p>暗号技術用途の乱数生成器は,暗号分野においては中核技術のひとつであるが,一度に大量の乱数を生成させる必要のある科学技術シミュレーションなどの用途には向かない。
上手く使い分けてほしい。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/remark/2016/03/mersenne-twister/">Mersenne Twister に関する覚え書き</a></li>
<li><a href="http://www.pcg-random.org/">PCG, A Family of Better Random Number Generators | PCG, A Better Random Number Generator</a></li>
<li><a href="http://news.mynavi.jp/news/2014/03/11/037/">/dev/randomではなく/dev/urandomを使うべき理由? | マイナビニュース</a></li>
<li><a href="https://qiita.com/po3rin/items/f28a8ce322cb1bd95175">与えられた重みに従ってランダムに値を返す「Weighted Random Selection」をGoで実装する! - Qiita</a></li>
<li><a href="https://zenn.dev/yoheimuta/articles/6de5816f5d721c">ある範囲に収まる乱数を得るために剰余(モジュロ)演算を書くとき、レビューするときに意識すること</a></li>
</ul>
<p><a href="https://text.baldanders.info/golang/bookmark/">Go 言語に関するブックマーク集はこちら</a>。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B015643CPE?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51t6yHHVwEL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B015643CPE?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">暗号技術入門 第3版 秘密の国のアリス</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2015-08-25 (Release 2015-09-17)</dd>
<dd>Kindle版</dd>
<dd>B015643CPE (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">SHA-3 や Bitcoin/Blockchain など新しい知見や技術要素を大幅追加。暗号技術を使うだけならこれ1冊でとりあえず無問題。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2015-09-20">2015-09-20</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 暗号技術入門 第3版 -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>ただし <a href="https://github.com/davidminor/gorand" title="davidminor/gorand: Basic golang implementation of a permuted congruential generator for pseudorandom number generation"><code>github.com/davidminor/gorand</code></a><code>/lcg</code> には不具合があって <code>Int63()</code> 関数で負の値を出力する場合がある。とりあえず fork 版の <a href="https://github.com/davidminor/gorand" title="spiegel-im-spiegel/gorand: Basic golang implementation of a permuted congruential generator for pseudorandom number generation"><code>github.com/spiegel-im-spiegel/gorand</code></a><code>/lcg</code> で修正している。 Pull request も出したけど,古いコードだし,もうメンテしてないかなぁ。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>$2^{19937}-1$ はメルセンヌ素数で <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> の名前の由来になっている。 <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> では周期サイズごとに複数の実装があるが, $2^{19937}-1$ がポピュラーな実装として広く使われているようだ。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>におけるオブジェクトの多態性については「<a href="https://text.baldanders.info/golang/object-oriented-programming/">Go 言語における「オブジェクト」</a>」を参考にどうぞ。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:4">
<p><code>/dev/urandom</code> はハードウェア・デバイスから十分なエントロピー源が得られない場合は内部で疑似乱数生成器を使用する。このため一時は <code>/dev/urandom</code> の脆弱性が疑われたが,現時点では事実上は問題ないとされている。一方で,スマートデバイスのような場合はハードウェア・デバイスからのエントロピー源だけでは外部から推測され易いため,性能のよい疑似乱数生成器を組み合わせるほうが有効になる場合もあるようだ。 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:5">
<p><a href="https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa379942.aspx" title="CryptGenRandom function"><code>CryptGenRandom</code></a> 関数の内部実装は公開されていないが,やはりキーボードやマウス等のデバイスの挙動をエントロピー源とし, NIST の SP800-90 勧告に従った実装をしているようである。余談だが SP800-90 は乱数生成の一部のアルゴリズムで脆弱性が発見され(これがまた NSA 絡みだったものだから大騒ぎになった),現在は修正版の <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf" title="Recommendation for Random Number Generation Using Deterministic Random Bit Generators">SP800-90A Revision 1</a>が発行されている。(参考:<a href="http://www.cryptrec.go.jp/topics/cryptrec_20131106_dual_ec_drbg.html">擬似乱数生成アルゴリズム Dual_EC_DRBG について</a>) <a href="#fnref:5" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
Mersenne Twister に関する覚え書き
tag:text.Baldanders.info,2016-03-17:/remark/2016/03/mersenne-twister/
2016-03-17T12:41:22+00:00
2021-12-04T02:40:05+00:00
「ズンドコキヨシ」で興味が出たので [Mersenne Twister] について調べている。適宜追加予定。
Spiegel
https://baldanders.info/profile/
<p><a href="http://qiita.com/spiegel-im-spiegel/items/6a5bc07dbfa46a328e26" title="「ズンドコキヨシ」と擬似乱数 - Qiita">「ズンドコキヨシ」で興味が出た</a>ので <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> について調べている。
適宜追加予定。</p>
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> とは<a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/" title="Makoto Matsumoto Home Page">松本眞</a>・西村拓士両氏によって1996年に発表された擬似乱数生成アルゴリズムである。
他の擬似乱数生成アルゴリズムと比べて以下の特徴があるそうだ。
(「<a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/what-is-mt.html" title="What & how is MT?">Mersenne Twister とは?</a>」より)</p>
<ul>
<li>従来の様々な生成法の欠点を考慮して設計されています。</li>
<li>従来にない長周期, 高次元均等分布を持ちます。(周期が $2^{19937}-1$ で<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>、623次元超立方体の中に 均等に分布することが証明されています。)</li>
<li>生成速度がかなり速い。(処理系にもよりますが、パイプライン処理やキャッシュメモリ のあるシステムでは、Cの標準ライブラリの <code>rand()</code> より高速なこと もあります。なお、開発当時には cokus 版は <code>rand()</code> より4倍程度高速でしたが、その後 ANSI-C の <code>rand()</code> が LCG 法から lagged-fibonacci に 変更されたこともあり、2002年現在 rand と MT の速度差はあまりありません。)</li>
<li>メモリ効率が良い。(32ビット以上のマシン用に設計された <code>mt19937.c</code> は、 624ワードのワーキングメモリを消費するだけです。 1ワードは32ビット長とします。</li>
</ul>
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> が主に使われるのは科学シミュレーション(最近流行りのモンテカルロ法とか)だが,比較的メモリ効率がよいためゲームなどでも使われるらしい<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。
また <a href="http://kikakurui.com/z9/Z9031-2012-01.html">JIS Z 9031</a> の附属書 B にも <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> のコードが掲載されている。
改良版の <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index-jp.html">SFMT (SIMD-oriented Fast Mersenne Twister)</a> や $2^{127}-1$ 周期の軽量版 <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index-jp.html">TinyMT</a> などがある。</p>
<p>オリジナルのコードは <a href="https://github.com/" title="GitHub">GitHub</a> で公開されている。</p>
<ul>
<li><a href="https://github.com/MersenneTwister-Lab">MersenneTwister-Lab</a>
<ul>
<li><a href="https://github.com/MersenneTwister-Lab/SFMT" title="MersenneTwister-Lab/SFMT: SIMD-oriented Fast Mersenne Twister">SFMT</a></li>
<li><a href="https://github.com/MersenneTwister-Lab/dSFMT" title="MersenneTwister-Lab/dSFMT: Double precision SIMD-oriented Fast Mersenne Twister">dSFMT</a> (倍精度浮動小数点擬似乱数を直接生成できる)</li>
<li><a href="https://github.com/MersenneTwister-Lab/TinyMT" title="MersenneTwister-Lab/TinyMT: Tiny Mersenne Twister">TinyMT</a></li>
</ul>
</li>
</ul>
<p>主に C 言語で記述されており BSD ライセンスで提供されている<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>。
また C++, PHP, Python, Ruby などの言語では標準で組み込まれている。</p>
<ul>
<li><a href="http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine">std::mersenne_twister_engine - cppreference.com</a></li>
<li><a href="http://php.net/manual/en/function.mt-srand.php">PHP: mt_srand - Manual</a></li>
<li><a href="https://docs.python.org/3.3/library/random.html">9.6. random — Generate pseudo-random numbers — Python 3.3.6 documentation</a>
<ul>
<li><a href="https://docs.python.org/2.7/library/random.html">9.6. random — Generate pseudo-random numbers — Python 2.7.11 documentation</a></li>
</ul>
</li>
<li><a href="http://ruby-doc.org/core-2.3.0/Random.html">Class: Random (Ruby 2.3.0)</a></li>
</ul>
<p>これら以外では Java や <a href="https://go.dev/">Go</a> などによる実装がある。</p>
<ul>
<li><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/JAVA/index-jp.html">TinyMT Java Implementation (Japanese)</a> (オリジナル)</li>
<li><a href="http://cs.gmu.edu/~sean/research/">Sean Luke : Code</a> に <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> の Java 実装が紹介されている</li>
<li><a href="https://github.com/seehuhn/mt19937">seehuhn/mt19937: An implementation of Takuji Nishimura’s and Makoto Matsumoto’s Mersenne Twister pseudo random number generator in Go.</a> (GPL ライセンスなので取り扱いに注意)</li>
</ul>
<h2>ブックマーク</h2>
<ul>
<li><span><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/TEACH/0407-2.pdf">有限体の擬似乱数への応用 <sup><i class="far fa-file-pdf"></i></sup></a></span></li>
<li><span><a href="http://www.soi.wide.ad.jp/class/20010000/slides/03/sfc2002.pdf">間違いだらけの疑似乱数選び <sup><i class="far fa-file-pdf"></i></sup></a></span></li>
<li><a href="http://www001.upp.so-net.ne.jp/isaku/rand.html">良い乱数・悪い乱数</a></li>
<li><a href="http://theo.phys.sci.hiroshima-u.ac.jp/~ishikawa/PRNG/README.jp.html">Multiple stream Mersenne Twister PRNG</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>$2^{19937}-1$ はメルセンヌ素数で <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> の名前の由来になっている。 <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> では周期サイズごとに複数の実装があるが, $2^{19937}-1$ がポピュラーな実装として広く使われているようだ。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> は「予測可能」であるため暗号技術など高いセキュリティが要求される場合には使えない。暗号技術における乱数生成器の要件については <a href="http://tools.ietf.org/html/rfc4086" title="RFC 4086 - Randomness Requirements for Security">RFC 4086</a> (<a href="https://www.ipa.go.jp/security/rfc/RFC4086JA.html">IPA による日本語訳</a>)などが参考になる。なお <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html" title="Mersenne Twister: A random number generator (since 1997/10)">Mersenne Twister</a> を応用した <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/CRYPTMT/index-jp.html">CryptMT</a> というのはある。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3">
<p><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/license.html" title="Mersenne Twisterの商用について">MIT ライセンスでの利用も可能</a>らしい。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>