List of Algorithm - text.Baldanders.info
tag:text.Baldanders.info,2015-09-17:/tags
2015-09-17T21:23:42+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
素数探索アルゴリズムで遊ぶ
tag:text.Baldanders.info,2015-09-17:/golang/search-prime-numbers/
2015-09-17T12:23:42+00:00
2020-01-15T11:57:05+00:00
これまた,みんな大好き素数探索アルゴリズム
Spiegel
https://baldanders.info/profile/
<p>(初出: <a href="http://qiita.com/spiegel-im-spiegel/items/047a9bd6436e6391ddd4">はじめての Go 言語 (on Windows) その2 - Qiita</a>)</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>は公式のドキュメントがとても充実していて(ただしほぼ英語だけど),私のような初学者に易しい環境といえる。</p>
<ul>
<li><a href="https://golang.org/doc/">Documentation - The Go Programming Language</a> : 言語仕様に関するドキュメントはこちら(<a href="http://golang-jp.org/doc/">一部日本語化</a>されている)</li>
<li><a href="https://golang.org/pkg/">Packages - The Go Programming Language</a> : 標準パッケージのドキュメントはこちら(<a href="http://golang-jp.org/pkg/">一部日本語化</a>されている)</li>
</ul>
<p>とはいえ,コードが実際にどのように機能するかは書いてみないと分からない部分もある。
なので,今回からは実際にコードを書きながら言語の癖のようなものを調べていくことにする。
仕事に使うなら厳密な評価が必要だけど,今のところはそんな予定もないし,まずはテキトーで(笑)</p>
<p>早速,みんな大好き素数探索アルゴリズムで遊ぶ。</p>
<h2>素数の定義</h2>
<p>一応,素数(prime number)の定義を以下に示す。</p>
<blockquote>
<p>1 と自分自身以外に正の約数を持たない 1 より大きい自然数</p>
</blockquote>
<p>ここで自然数(natural number)は「ペアノの公理」に従う(0 が自然数に含まれるかどうかについては色々あるみたいだが,素数の定義には影響がないので,ここでは無視する)。</p>
<ul>
<li><a href="https://ja.wikipedia.org/wiki/%E3%83%9A%E3%82%A2%E3%83%8E%E3%81%AE%E5%85%AC%E7%90%86">ペアノの公理 - Wikipedia</a></li>
<li><a href="http://qiita.com/taketo1024/items/2ab856d21bf9b9f30357">Swiftで自然数を作ってみた(ペアノの公理) - Qiita</a></li>
</ul>
<p>ちなみに結城浩さんの『<a href="https://www.amazon.co.jp/exec/obidos/ASIN/B00I8AT1D6/baldandersinf-22/">数学ガール/ゲーデルの不完全性定理</a>』にペアノの公理について分かりやすく解説した章がある。
お勧め。</p>
<h2 id="alg1">素数探索アルゴリズム(その1)</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">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">"time"</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">max</span> <span class="o">:=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int64</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// 素数のリスト
</span></span></span><span class="line"><span class="cl"><span class="c1"></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 class="c1">//Start
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">n</span> <span class="o">:=</span> <span class="mi">2</span><span class="p">;</span> <span class="nx">n</span> <span class="o"><=</span> <span class="nx">max</span><span class="p">;</span> <span class="nx">n</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">flag</span> <span class="o">:=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">m</span> <span class="o">:=</span> <span class="mi">2</span><span class="p">;</span> <span class="nx">m</span> <span class="p"><</span> <span class="nx">n</span><span class="p">;</span> <span class="nx">m</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">m</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span> <span class="c1">// n が m で割り切れる → 素数ではない
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">flag</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</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="k">if</span> <span class="nx">flag</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes</span><span class="p">,</span> <span class="nb">int64</span><span class="p">(</span><span class="nx">n</span><span class="p">))</span> <span class="c1">// 素数を追加
</span></span></span><span class="line"><span class="cl"><span class="c1"></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">goal</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span> <span class="c1">//Goal
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%v 以下の素数: %v\n"</span><span class="p">,</span> <span class="nx">max</span><span class="p">,</span> <span class="nx">primes</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">Printf</span><span class="p">(</span><span class="s">"%v 経過"</span><span class="p">,</span> <span class="nx">goal</span><span class="p">.</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">start</span><span class="p">))</span> <span class="c1">//経過時間を表示
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>実行結果はこんな感じ。</p>
<pre tabindex="0"><code>C:>go run prime01.go
100 以下の素数: [2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]
0 経過
</code></pre><p>この値を覚えておいてね。
検算に使うから。</p>
<h2 id="alg2">素数探索アルゴリズム(その2: エラトステネスの篩の変形)</h2>
<p>もう少しだけ効率的に素数を探すアルゴリズムとして「<a href="https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%A9%E3%83%88%E3%82%B9%E3%83%86%E3%83%8D%E3%82%B9%E3%81%AE%E7%AF%A9" title="エラトステネスの篩 - Wikipedia">エラトステネスの篩</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="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">"time"</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">max</span> <span class="o">:=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int64</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// 素数のリスト
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">isNotPrime</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">bool</span><span class="p">,</span> <span class="nx">max</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// false で初期化される(全てを素数候補とする)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">isNotPrime</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="kc">true</span> <span class="c1">// 0 は非素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">isNotPrime</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="p">=</span> <span class="kc">true</span> <span class="c1">// 1 は非素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></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 class="c1">//Start
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">n</span> <span class="o">:=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">;</span> <span class="nx">n</span><span class="o">*</span><span class="nx">n</span> <span class="o"><=</span> <span class="nx">max</span><span class="p">;</span> <span class="nx">n</span><span class="o">++</span> <span class="p">{</span> <span class="c1">// √max まで篩にかける
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">if</span> <span class="p">!</span><span class="nx">isNotPrime</span><span class="p">[</span><span class="nx">n</span><span class="p">]</span> <span class="p">{</span> <span class="c1">// n は素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes</span><span class="p">,</span> <span class="nb">int64</span><span class="p">(</span><span class="nx">n</span><span class="p">))</span> <span class="c1">// 素数を追加
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">m</span> <span class="o">:=</span> <span class="mi">2</span><span class="p">;</span> <span class="nx">n</span><span class="o">*</span><span class="nx">m</span> <span class="o"><=</span> <span class="nx">max</span><span class="p">;</span> <span class="nx">m</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">isNotPrime</span><span class="p">[</span><span class="nx">n</span><span class="o">*</span><span class="nx">m</span><span class="p">]</span> <span class="p">=</span> <span class="kc">true</span> <span class="c1">// max 以下の n の倍数を全て非素数とする
</span></span></span><span class="line"><span class="cl"><span class="c1"></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="k">for</span> <span class="p">;</span> <span class="nx">n</span> <span class="o"><=</span> <span class="nx">max</span><span class="p">;</span> <span class="nx">n</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">isNotPrime</span><span class="p">[</span><span class="nx">n</span><span class="p">]</span> <span class="p">{</span> <span class="c1">// n は素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes</span><span class="p">,</span> <span class="nb">int64</span><span class="p">(</span><span class="nx">n</span><span class="p">))</span> <span class="c1">// 素数を追加
</span></span></span><span class="line"><span class="cl"><span class="c1"></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">goal</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span> <span class="c1">//Goal
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%v 以下の素数: %v\n"</span><span class="p">,</span> <span class="nx">max</span><span class="p">,</span> <span class="nx">primes</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">Printf</span><span class="p">(</span><span class="s">"%v 経過"</span><span class="p">,</span> <span class="nx">goal</span><span class="p">.</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">start</span><span class="p">))</span> <span class="c1">//経過時間を表示
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><pre tabindex="0"><code>C:>go run prime01b.go
100 以下の素数: [2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]
0 経過
</code></pre><p>割り算がない。
ブラボー!</p>
<p>ただし「<a href="https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%A9%E3%83%88%E3%82%B9%E3%83%86%E3%83%8D%E3%82%B9%E3%81%AE%E7%AF%A9" title="エラトステネスの篩 - Wikipedia">エラトステネスの篩</a>」は決まった範囲を探索するものなので少々使いづらい。
しかも掛け算を使うので大きな数を探索するのには向いていない。
そこで「<a href="https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%A9%E3%83%88%E3%82%B9%E3%83%86%E3%83%8D%E3%82%B9%E3%81%AE%E7%AF%A9" title="エラトステネスの篩 - Wikipedia">エラトステネスの篩</a>」で使われている以下の素数の特徴を最初のアルゴリズムに加えてみる。</p>
<ol>
<li>2 以上の全ての自然数はひとつ以上の素数の積で構成される(この素数の集合を素因数(prime factor)という)。したがってある数が素数か否かの判定は,その数より小さい素数のみで調べればよい</li>
<li>更に,積の可換則(commutative property あるいは交換法則)により,自然数 $n$ が素数か否か判定する場合は $\sqrt{n}$ 以下の素数で調べればよい<br>
(たとえば 35 の素因数は 5 と 7 だが, $5 \times 7 = 7 \times 5 = 35$ なので,直前の素数 31 まで回さずとも 3 および 5 ($\le \sqrt{35}$) まで調べれば判定できる)</li>
<li>素数の定義から 2 が素数であることは自明なので(1 と 2 の間に自然数は存在しない), 2 より大きい 2 の倍数(すなわち偶数)については判定しなくてもよく,対象となる自然数は 3 以上の奇数のみでいいことになる。</li>
</ol>
<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">"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">"time"</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">primes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int64</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// 素数のリスト
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes_f</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float64</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// 素数のリスト(浮動小数点へのキャスト)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="mi">2</span> <span class="c1">// 2 は素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes_f</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="mf">2.0</span> <span class="c1">// 2 は素数(浮動小数点)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kd">var</span> <span class="nx">max</span> <span class="kt">int64</span> <span class="p">=</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl">
</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 class="c1">// Start
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kd">var</span> <span class="nx">n</span> <span class="kt">int64</span> <span class="p">=</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">n</span> <span class="p">=</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">n</span> <span class="p"><</span> <span class="nx">max</span><span class="p">;</span> <span class="nx">n</span> <span class="o">+=</span> <span class="mi">2</span> <span class="p">{</span> <span class="c1">// 3 から始まる奇数のみを探索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">flag</span> <span class="o">:=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="nx">f</span> <span class="o">:=</span> <span class="nb">float64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="c1">// 浮動小数点に cating
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">rf</span> <span class="o">:=</span> <span class="nx">math</span><span class="p">.</span><span class="nf">Sqrt</span><span class="p">(</span><span class="nx">f</span><span class="p">)</span> <span class="c1">// n に対して √n をとる
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nb">len</span><span class="p">(</span><span class="nx">primes</span><span class="p">);</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span> <span class="c1">// 2 より大きい既知の素数でチェックする
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">if</span> <span class="nx">primes_f</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">></span> <span class="nx">rf</span> <span class="p">{</span> <span class="c1">// n に対して √n 以下の素数まで探索すればよい
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">break</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">primes</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span> <span class="c1">// n が既知の素数で割り切れる → 素数ではない
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">flag</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</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="k">if</span> <span class="nx">flag</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="c1">// 素数を追加
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes_f</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes_f</span><span class="p">,</span> <span class="nx">f</span><span class="p">)</span> <span class="c1">// 素数を追加(浮動小数点)
</span></span></span><span class="line"><span class="cl"><span class="c1"></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">goal</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span> <span class="c1">// Goal
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%v 以下の素数: %v\n"</span><span class="p">,</span> <span class="nx">max</span><span class="p">,</span> <span class="nx">primes</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">Printf</span><span class="p">(</span><span class="s">"%v 経過"</span><span class="p">,</span> <span class="nx">goal</span><span class="p">.</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">start</span><span class="p">))</span> <span class="c1">// 経過時間を表示
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>実行結果はこんな感じ。</p>
<pre tabindex="0"><code>C:>go run prime02.go
100 以下の素数: [2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]
0 経過
</code></pre><h3>slice と make() と append()</h3>
<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="nx">primes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int64</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// 素数のリスト
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">primes_f</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float64</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// 素数のリスト(浮動小数点へのキャスト)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">primes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="mi">2</span> <span class="c1">// 2 は素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">primes_f</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="mf">2.0</span> <span class="c1">// 2 は素数(浮動小数点)
</span></span></span></code></pre></div><p>の変数 <code>primes</code> および <code>primes_f</code> は <a href="http://golang.org/ref/spec#Slice_types">slice</a> と呼ばれる可変長の配列型である。
更に組み込み関数 <code>make()</code> は <a href="http://golang.org/ref/spec#Slice_types">slice</a>, <a href="http://golang.org/ref/spec#Map_types">map</a>, <a href="http://golang.org/ref/spec#Channel_types">channel</a> のみ使用可能なメモリ割り当て関数である。
ちなみに <a href="http://golang.org/ref/spec#Slice_types">slice</a>, <a href="http://golang.org/ref/spec#Map_types">map</a>, <a href="http://golang.org/ref/spec#Channel_types">channel</a> 以外は <code>new()</code> を使う。
<a href="http://golang.org/ref/spec#Slice_types">slice</a>, <a href="http://golang.org/ref/spec#Map_types">map</a>, <a href="http://golang.org/ref/spec#Channel_types">channel</a> のみ特別なのは,これらの型は初期値と内部状態を持つためである。</p>
<p><a href="http://golang.org/ref/spec#Slice_types">slice</a> に要素を追加する場合は <code>append()</code> 関数を使えばいいのだが,これが結構クセがある。
<code>append()</code> 関数では <a href="http://golang.org/ref/spec#Slice_types">slice</a> の容量(capacity)がいっぱいになると新たにメモリを確保してオリジナルの内容をコピーする。
つまりポインタが変わってしまうのだ。(メモリの割り当て方のパターンにも注目)</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="s">"fmt"</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">a</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// 空の配列を用意
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Slice(%02d) : %p : %v (%v)\n"</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nb">cap</span><span class="p">(</span><span class="nx">a</span><span class="p">))</span> <span class="c1">// 配列の表示(初期状態)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">num</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">num</span> <span class="o"><=</span> <span class="mi">17</span><span class="p">;</span> <span class="nx">num</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">a</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">num</span><span class="p">)</span> <span class="c1">//配列要素の追加
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Slice(%02d) : %p : %v (%v)\n"</span><span class="p">,</span> <span class="nx">num</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nb">cap</span><span class="p">(</span><span class="nx">a</span><span class="p">))</span> <span class="c1">//配列の表示
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><pre tabindex="0"><code>C:>go run slice.go
Slice(00) : 0x5cebb8 : [] (0)
Slice(01) : 0xc082002340 : [1] (1)
Slice(02) : 0xc082002380 : [1 2] (2)
Slice(03) : 0xc082006740 : [1 2 3] (4)
Slice(04) : 0xc082006740 : [1 2 3 4] (4)
Slice(05) : 0xc0820083c0 : [1 2 3 4 5] (8)
Slice(06) : 0xc0820083c0 : [1 2 3 4 5 6] (8)
Slice(07) : 0xc0820083c0 : [1 2 3 4 5 6 7] (8)
Slice(08) : 0xc0820083c0 : [1 2 3 4 5 6 7 8] (8)
Slice(09) : 0xc082050000 : [1 2 3 4 5 6 7 8 9] (16)
Slice(10) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10] (16)
Slice(11) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11] (16)
Slice(12) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12] (16)
Slice(13) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13] (16)
Slice(14) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14] (16)
Slice(15) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] (16)
Slice(16) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] (16)
Slice(17) : 0xc082056000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17] (32)
</code></pre><p>容量が変化するごとにポインタ値も変化していることがお分かりだろうか。</p>
<p>ちなみに Go コンパイラは,返値を無視するコーディングに対してエラーを吐く。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">a</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">num</span><span class="p">)</span>
</span></span></code></pre></div><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="nb">append</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">num</span><span class="p">)</span>
</span></span></code></pre></div><p>とすると</p>
<pre tabindex="0"><code>C:>go run prime02.go
# command-line-arguments
.\slice.go:9: append(a, num) evaluated but not used
</code></pre><p>とエラーになる。</p>
<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="nx">a</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span></code></pre></div><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="nx">a</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">32</span><span class="p">)</span>
</span></span></code></pre></div><p>とすると</p>
<pre tabindex="0"><code>C:>go run slice.go
Slice(00) : 0xc082050000 : [] (32)
Slice(01) : 0xc082050000 : [1] (32)
Slice(02) : 0xc082050000 : [1 2] (32)
Slice(03) : 0xc082050000 : [1 2 3] (32)
Slice(04) : 0xc082050000 : [1 2 3 4] (32)
Slice(05) : 0xc082050000 : [1 2 3 4 5] (32)
Slice(06) : 0xc082050000 : [1 2 3 4 5 6] (32)
Slice(07) : 0xc082050000 : [1 2 3 4 5 6 7] (32)
Slice(08) : 0xc082050000 : [1 2 3 4 5 6 7 8] (32)
Slice(09) : 0xc082050000 : [1 2 3 4 5 6 7 8 9] (32)
Slice(10) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10] (32)
Slice(11) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11] (32)
Slice(12) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12] (32)
Slice(13) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13] (32)
Slice(14) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14] (32)
Slice(15) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] (32)
Slice(16) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] (32)
Slice(17) : 0xc082050000 : [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17] (32)
</code></pre><p>となる。
メモリ割り当ては意外に高コストの操作なので, <a href="http://golang.org/ref/spec#Slice_types">slice</a> を扱う場合はこの辺がチューニング・ポイントになるだろう。</p>
<h2>100万個目の素数</h2>
<p>上のコードを少し修正して $x$ 個目の素数を調べることにしよう。</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">"flag"</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">"os"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"strconv"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</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="c1">//コマンドライン引数の解析
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">algno</span> <span class="o">:=</span> <span class="nx">flag</span><span class="p">.</span><span class="nf">Int</span><span class="p">(</span><span class="s">"alg"</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"0: Basic algorithm , 1: Sieve of Eratosthenes"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">flag</span><span class="p">.</span><span class="nf">Parse</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">args</span> <span class="o">:=</span> <span class="nx">flag</span><span class="p">.</span><span class="nf">Args</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="o">*</span><span class="nx">algno</span> <span class="p"><</span> <span class="mi">0</span> <span class="o">||</span> <span class="o">*</span><span class="nx">algno</span> <span class="p">></span> <span class="mi">1</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">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">ErrInvalid</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="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</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">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="nx">os</span><span class="p">.</span><span class="nx">ErrInvalid</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">max</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">strconv</span><span class="p">.</span><span class="nf">ParseInt</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">64</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="nx">fmt</span><span class="p">.</span><span class="nf">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="nx">err</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="k">if</span> <span class="nx">max</span> <span class="o"><=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">max</span> <span class="p">=</span> <span class="mi">1</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">//素数探索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">prime</span> <span class="o">:=</span> <span class="nb">int64</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">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 class="c1">// Start
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">switch</span> <span class="o">*</span><span class="nx">algno</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prime</span> <span class="p">=</span> <span class="nf">LastPrimeE</span><span class="p">(</span><span class="nx">max</span><span class="p">)</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="nx">prime</span> <span class="p">=</span> <span class="nf">LastPrimeB</span><span class="p">(</span><span class="nx">max</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">goal</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">()</span> <span class="c1">// Goal
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%v 個目の素数: %v\n"</span><span class="p">,</span> <span class="nx">max</span><span class="p">,</span> <span class="nx">prime</span><span class="p">)</span> <span class="c1">// max 個目の素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%v 経過\n"</span><span class="p">,</span> <span class="nx">goal</span><span class="p">.</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">start</span><span class="p">))</span> <span class="c1">// 経過時間を表示
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><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">LastPrimeB</span><span class="p">(</span><span class="nx">max</span> <span class="kt">int64</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">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">n</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="p">;</span> <span class="nx">n</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">flag</span> <span class="o">:=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">m</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="nx">m</span> <span class="p"><</span> <span class="nx">n</span><span class="p">;</span> <span class="nx">m</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">m</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span> <span class="c1">// n が m で割り切れる → 素数ではない
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">flag</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</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="k">if</span> <span class="nx">flag</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">count</span> <span class="o">>=</span> <span class="nx">max</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">n</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="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">LastPrimeE</span><span class="p">(</span><span class="nx">max</span> <span class="kt">int64</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">max</span> <span class="o"><=</span> <span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int64</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">max</span><span class="p">)</span> <span class="c1">// 素数のリスト
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes_f</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">float64</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">max</span><span class="p">)</span> <span class="c1">// 素数のリスト(浮動小数点へのキャスト)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="mi">2</span> <span class="c1">// 2 は素数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes_f</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="mf">2.0</span> <span class="c1">// 2 は素数(浮動小数点)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</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">for</span> <span class="nx">n</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> <span class="p">;</span> <span class="nx">n</span> <span class="o">+=</span> <span class="mi">2</span> <span class="p">{</span> <span class="c1">// 3 から始まる奇数のみを探索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">flag</span> <span class="o">:=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="nx">f</span> <span class="o">:=</span> <span class="nb">float64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="c1">// 浮動小数点に cating
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">rf</span> <span class="o">:=</span> <span class="nx">math</span><span class="p">.</span><span class="nf">Sqrt</span><span class="p">(</span><span class="nx">f</span><span class="p">)</span> <span class="c1">// n に対して √n をとる
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="p"><</span> <span class="nb">len</span><span class="p">(</span><span class="nx">primes</span><span class="p">);</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span> <span class="c1">// 2 より大きい既知の素数でチェックする
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">if</span> <span class="nx">primes_f</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">></span> <span class="nx">rf</span> <span class="p">{</span> <span class="c1">// n に対して √n 以下の素数まで探索すればよい
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">break</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">primes</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span> <span class="c1">// n が既知の素数で割り切れる → 素数ではない
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">flag</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</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="k">if</span> <span class="nx">flag</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">count</span> <span class="o">>=</span> <span class="nx">max</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">n</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="c1">// 素数を追加
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">primes_f</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">primes_f</span><span class="p">,</span> <span class="nx">f</span><span class="p">)</span> <span class="c1">// 素数を追加(浮動小数点)
</span></span></span><span class="line"><span class="cl"><span class="c1"></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>今後のためにコマンドライン解析の部分と実際の素数探索アルゴリズムを分けている。
まず検算。
25個目の素数が 97 なら OK。</p>
<pre tabindex="0"><code>C:>go run prime03.go -alg=0 25
25 個目の素数: 97
0 経過
C:>go run prime03.go -alg=1 25
25 個目の素数: 97
0 経過
</code></pre><p>では実際に動かしてみよう。
まずは「<a href="#alg1">その1</a>」のアルゴリズムから。</p>
<pre tabindex="0"><code>C:>go run prime03.go -alg=0 100
100 個目の素数: 541
0 経過
C:>go run prime03.go -alg=0 10000
10000 個目の素数: 104729
4.4072521s 経過
</code></pre><p>100万個目の素数は有意の時間で見つかりませんでした orz</p>
<p>次に「<a href="#alg2">その2</a>」のアルゴリズムで。</p>
<pre tabindex="0"><code>C:>go run prime03.go --alg=1 100
100 個目の素数: 541
0 経過
C:>go run prime03.go --alg=1 10000
10000 個目の素数: 104729
7.0004ms 経過
C:>go run prime03.go --alg=1 1000000
1000000 個目の素数: 15485863
4.9042805s 経過
C:>go run prime03.go --alg=1 10000000
10000000 個目の素数: 179424673
2m13.8686568s 経過
</code></pre><p>というわけで,100万個目の素数探索に5秒弱,1000万個目の素数探索に2分ちょっとかかってしまった。
まぁ,でも,こんなもんか。</p>
<h2 id="alg3">素数探索アルゴリズム(その3: エラトステネスの篩を並行処理で)</h2>
<p>これまでのアルゴリズムは基本的に2重のループで値を順番に付き合わせているだけだったが,この部分を並行処理で行えば速いんじゃね? と思うよね。</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>で並行処理を行うには <a href="http://golang.org/ref/spec#Go_statements">goroutine</a>(「ゴルーチン」と読むらしい)を使う。
また <a href="http://golang.org/ref/spec#Go_statements">goroutine</a> の worker 間ではメモリ共有ができないため, <a href="http://golang.org/ref/spec#Channel_types">channel</a> を使い message-passing 方式<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>で通信を行う。</p>
<p>で,実際に <a href="http://golang.jp/go_tutorial#index12">チュートリアルには並行処理を使った素数探索アルゴリズムが紹介</a>されている<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。
いくつかサイトを巡ったが,このやり方がもっとも素直なようだ(後述するが速いわけではない)。
そこで,このコードを流用させてもらうことにした。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">LastPrimeE2</span><span class="p">(</span><span class="nx">max</span> <span class="kt">int64</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">max</span> <span class="o"><=</span> <span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">2</span> <span class="c1">// 最初の素数は2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="o">:=</span> <span class="nf">sieve</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prime</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">primes</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">count</span> <span class="o">>=</span> <span class="nx">max</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">prime</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></span><span class="line"><span class="cl"><span class="c1">// 素数候補の数を生成する
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">generate</span><span class="p">()</span> <span class="kd">chan</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int64</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">for</span> <span class="nx">n</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> <span class="p">;</span> <span class="nx">n</span> <span class="o">+=</span> <span class="mi">2</span> <span class="p">{</span> <span class="c1">// 3 以降の奇数を送信(2 以外の偶数は素数ではない)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">n</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="k">return</span> <span class="nx">ch</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">// 素数 'prime' に対するフィルタ
</span></span></span><span class="line"><span class="cl"><span class="c1">// 'prime' で割り切れない値のみ通過可能
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">filter</span><span class="p">(</span><span class="nx">in</span> <span class="kd">chan</span> <span class="kt">int64</span><span class="p">,</span> <span class="nx">prime</span> <span class="kt">int64</span><span class="p">)</span> <span class="kd">chan</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int64</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">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">n</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">in</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">prime</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o"><-</span> <span class="nx">n</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="k">return</span> <span class="nx">out</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">// エラトステネスの篩
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">sieve</span><span class="p">()</span> <span class="kd">chan</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int64</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="nx">ch</span> <span class="o">:=</span> <span class="nf">generate</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prime</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o"><-</span> <span class="nx">prime</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="p">=</span> <span class="nf">filter</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="nx">prime</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="k">return</span> <span class="nx">out</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>そうそう。
<a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>では関数は全て関数閉包(closure)として機能する。</p>
<p><code>main</code> 関数も少しいじって <code>-alg=2</code> でこのアルゴリズムを起動するようにする。
まずは検算ね。</p>
<pre tabindex="0"><code>C:>go run prime04.go -alg=2 25
25 個目の素数: 97
0 経過
</code></pre><p>じゃあ,早速うごかしてみよっか。</p>
<pre tabindex="0"><code>C:>go run prime04.go -alg=2 100
100 個目の素数: 541
2.0002ms 経過
C:>go run prime04.go -alg=2 10000
10000 個目の素数: 104729
4.2002402s 経過
</code></pre><p>100万個目の素数は有意の時間で見つかりませんでした orz</p>
<p>まぁアルゴリズム的に「篩」っぽくはあるんだけどね。</p>
<p>ある値が素数であると判定されるためには,その値より小さい全ての素数フィルタを通過しなければならない(つまり「<a href="#alg2">その2</a>」で紹介した特徴の2番目を全く生かせていない)。
これが致命的。
しかもこのフィルタ処理 <code>filter()</code> は素数フィルタの生成も兼ねていて,前の素数フィルタの出力を次の素数フィルタの入力として連結しているのでスキップできない。</p>
<p>かなりインチキではあるけど,捜索範囲を「100万個目」までと限定し,「100万個目」の素数が 15,485,863 であると分かっているならもう少し速くできるかもしれない。
つまり以下のように改良する。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">LastPrimeE2</span><span class="p">(</span><span class="nx">max</span> <span class="kt">int64</span><span class="p">)</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">max</span> <span class="o"><=</span> <span class="mi">1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">2</span> <span class="c1">// 最初の素数は2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">count</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">primes</span> <span class="o">:=</span> <span class="nf">sieve</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">prime</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">primes</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">count</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">count</span> <span class="o">>=</span> <span class="nx">max</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">prime</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="k">return</span> <span class="nx">count</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">// 素数候補の数を生成する
</span></span></span><span class="line"><span class="cl"><span class="c1">// ただし上限を 15485863 とする
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">generate</span><span class="p">()</span> <span class="kd">chan</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int64</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">for</span> <span class="nx">n</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> <span class="nx">n</span> <span class="o"><=</span> <span class="mi">15485863</span><span class="p">;</span> <span class="nx">n</span> <span class="o">+=</span> <span class="mi">2</span> <span class="p">{</span> <span class="c1">// 3 以降の奇数を送信(2 以外の偶数は素数ではない)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">ch</span> <span class="o"><-</span> <span class="nx">n</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nb">close</span><span class="p">(</span><span class="nx">ch</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="k">return</span> <span class="nx">ch</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">// 素数 'prime' に対するフィルタ
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">filter</span><span class="p">(</span><span class="nx">in</span> <span class="kd">chan</span> <span class="kt">int64</span><span class="p">,</span> <span class="nx">prime</span> <span class="kt">int64</span><span class="p">)</span> <span class="kd">chan</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int64</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">for</span> <span class="nx">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">in</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">prime</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o"><-</span> <span class="nx">n</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="nb">close</span><span class="p">(</span><span class="nx">out</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="k">return</span> <span class="nx">out</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">// エラトステネスの篩
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">sieve</span><span class="p">()</span> <span class="kd">chan</span> <span class="kt">int64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kt">int64</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="nx">ch</span> <span class="o">:=</span> <span class="nf">generate</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fflag</span> <span class="o">:=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">prime</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">out</span> <span class="o"><-</span> <span class="nx">prime</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">fflag</span> <span class="o">&&</span> <span class="nx">prime</span><span class="o">*</span><span class="nx">prime</span> <span class="o"><=</span> <span class="mi">15485863</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ch</span> <span class="p">=</span> <span class="nf">filter</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="nx">prime</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// 素数が最大値の平方根(√15485863)より大きい場合はフィルタを作らず無条件に通す
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fflag</span> <span class="p">=</span> <span class="kc">false</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="nb">close</span><span class="p">(</span><span class="nx">out</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="k">return</span> <span class="nx">out</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>これで実行してみる。</p>
<pre tabindex="0"><code>C:>go run prime05.go -alg=2 100
100 個目の素数: 541
2.0001ms 経過
C:>go run prime05.go -alg=2 10000
10000 個目の素数: 104729
378.0216ms 経過
C:>go run prime05.go -alg=2 1000000
1000000 個目の素数: 15485863
39.4492564s 経過
</code></pre><p>おお。
ようやく有意の時間で探索できた。
それでも「<a href="#alg2">その2</a>」の10倍以上かかるけど。</p>
<p><a href="http://golang.org/ref/spec#Channel_types">channel</a> への送信データが有限個の場合は最後に <code>close(ch)</code> でクローズする。
一方 <a href="http://golang.org/ref/spec#Channel_types">channel</a> からの受信側は <a href="http://golang.org/ref/spec#For_statements">for range 構文</a>を使うことで安全に扱うことができる。
ただし上述の <code>sieve()</code> 関数では 変数 <code>ch</code> が新しい素数フィルタの出力に上書きされていくので <a href="http://golang.org/ref/spec#For_statements">for range 構文</a>は使えない。
その代わり以下の記述で <a href="http://golang.org/ref/spec#Channel_types">channel</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="nx">prime</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="o"><-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">!</span><span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</span> <span class="c1">// channel が閉じられた
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>今回はここまで。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="http://jxck.hatenablog.com/entry/20130414/1365960707">Go の並行処理 - Block Rockin’ Codes</a></li>
<li><a href="http://qiita.com/sudix/items/f95ef0e5bbd0cd3d4378">(翻訳)Goでのパイプラインとキャンセル - Qiita</a></li>
<li><a href="http://qiita.com/suin/items/eca21ed935115e5da2e8">Go: 計算なしのFizzBuzz - Qiita</a> : <a href="http://golang.org/ref/spec#Channel_types">channel</a> の説明するのにいいかも</li>
<li><a href="http://qiita.com/yuki2006/items/3f90e53ce74c6cff1608">Goのchannelの送受信用の型について - Qiita</a></li>
<li><a href="http://qiita.com/hondata/items/64776c79063e93bea9ed">Go言語のChannelは送信時にもブロックする - Qiita</a> : 意外と見落とす channel 送信時のブロック</li>
<li><a href="http://qiita.com/Jxck_/items/da3ca2db58734a966cac">Go - select loop の小ネタ - Qiita</a></li>
<li><a href="http://qiita.com/sudix/items/67d4cad08fe88dcb9a6d">Goのforとgoroutineでやりがちなミスとたった一つの冴えたgo vetと - Qiita</a></li>
<li><a href="http://qiita.com/tutuming/items/c0ffdd28001ee0e9320d">golang - x/net/context の実装パターン - Qiita</a> : <a href="https://godoc.org/golang.org/x/net/context">golang.org/x/net/context</a> を使って並行処理を細かく制御</li>
<li><a href="http://deeeet.com/writing/2014/07/30/golang-parallel-by-cpu/">Go言語でCPU数に応じて並列処理数を制限する | SOTA</a></li>
<li><a href="http://qiita.com/ymko/items/554e3630fefdc29393a8">やはり俺のgolangがCPUを一つしか使わないのはまちがっている。 - Qiita</a></li>
<li><a href="http://qiita.com/cia_rana/items/2a878181da41033ec1d8">Golangで「エラトステネスの篩」で「2.1秒で百万個」の素数を計算できる「無限シーケンス」を作ってみた - Qiita</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/B00I8AT1D6?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41I26OVyotL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1D6?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガール/ゲーデルの不完全性定理</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2009-10-23 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1D6 (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="2014-10-21">2014-10-21</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>message-passing 方式は Erlang などで一躍有名になったやつ。ただし Erlang ではプロセス間通信の手段として message-passing を使う。これは Actor と呼ばれている。 <a href="http://golang.org/ref/spec#Go_statements">goroutine</a> は「並行処理」であり「並列処理」ではない。また,いわゆる thread とも異なる。<a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>で並列処理を行うなら「<a href="http://deeeet.com/writing/2014/07/30/golang-parallel-by-cpu/">Go言語でCPU数に応じて並列処理数を制限する</a>」あたりが参考になる。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>ただし現在の<a href="https://golang.org/doc/">公式ドキュメント</a>には存在しない。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>