List of Greatest-Common-Divisor - text.Baldanders.info
tag:text.Baldanders.info,2017-09-23:/tags
2017-09-23T23:32:56+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
最大公約数と関数型プログラミング
tag:text.Baldanders.info,2017-09-23:/golang/greatest-common-divisor/
2017-09-23T14:32:56+00:00
2021-08-12T21:22:05+00:00
そうだ。最大公約数(greatest common divisor)の話をしよう。
Spiegel
https://baldanders.info/profile/
<ul>
<li><a href="https://qiita.com/rsky/items/a39070208eaea38394c5">配列の全ての要素の最大公約数を求める (Java 8, Python) - Qiita</a></li>
</ul>
<p>この記事を見て思いついた。
そうだ。
最大公約数(greatest common divisor)の話をしよう。</p>
<h2>最大公約数を求める</h2>
<p>まずは定義から。
最大公約数の定義は以下の通り。</p>
<figure>
<blockquote>2つ以上の正の整数に共通な約数(公約数)のうち最大のもの</blockquote></figure>
<p>折角なので何か例題を立ててみよう。</p>
<figure>
<blockquote><p><strong>例題1</strong></p>
<p>20 と 32 の最大公約数を求めよ。</p>
</blockquote></figure>
<p>簡単な数だし,まずは暗算で解いてみる。
それぞれの値を素因数分解すると以下のようになる。</p>
<figure><div class="mathjax">
\begin{align*}
20 &= 2^2 \times 5 \\
32 &= 2^5
\end{align*}
</div></figure>
<p>これにより最大公約数は $2^2 = 4$ だということが分かる。
簡単でよかったね。</p>
<h2>ユークリッドの互除法</h2>
<p>さて,最大公約数を求める機械向けの計算方法としては「<a href="https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95" title="ユークリッドの互除法 - Wikipedia">ユークリッドの互除法</a>」が有名である。
具体的な手順は以下の通り。</p>
<ol>
<li>32 を 20 で割った余りは 12</li>
<li>20 を 12 で割った余りは 8</li>
<li>12 を 8 で割った余りは 4</li>
<li>8 を 4 で割った余りは 0</li>
<li>したがって 32 と 20 の最大公約数は 4 である</li>
</ol>
<p>これを図形で表すとこんな感じになる。
(以下の<a href="https://ja.wikipedia.org/wiki/File:GCM_Of_20_And_32.gif" title="File_GCM Of 20 And 32.gif - Wikipedia">図は Wikipedia のもの</a>を拝借した。 <a href="https://creativecommons.org/licenses/by-sa/3.0/" title="Creative Commons — Attribution-ShareAlike 3.0 Unported — CC BY-SA 3.0">CC-BY-SA-3.0</a> で公開されている)</p>
<figure style='margin:0 auto;text-align:center;'><a href="https://ja.wikipedia.org/wiki/File:GCM_Of_20_And_32.gif"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/GCM_Of_20_And_32.gif/640px-GCM_Of_20_And_32.gif" srcset="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/GCM_Of_20_And_32.gif/640px-GCM_Of_20_And_32.gif 640w" sizes="(min-width:600px) 500px, 80vw" alt="From Wikipedia" loading="lazy"></a><figcaption><div><a href="https://ja.wikipedia.org/wiki/File:GCM_Of_20_And_32.gif">From Wikipedia</a></div></figcaption>
</figure>
<p>今回は<a href="https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95" title="ユークリッドの互除法 - Wikipedia">ユークリッドの互除法</a>の証明は割愛するとして<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>,上記の手順の 1 から 4 は再帰処理になっていることが分かる。
というわけで,こんな感じのコードを組んでみる。
(だいぶ端折ったコードでゴメン)</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">gcd</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">b</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">a</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="nf">gcd</span><span class="p">(</span><span class="nx">b</span><span class="p">,</span> <span class="nx">a</span><span class="o">%</span><span class="nx">b</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></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="nf">gcd</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="mi">20</span><span class="p">))</span> <span class="c1">// 4
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>これで実行結果は 4 になる。</p>
<p>実は <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>にも最大公約数を求める関数が標準パッケージ <a href="https://golang.org/pkg/math/big/" title="big - The Go Programming Language"><code>math/big</code></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">"math/big"</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">gcd</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</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">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</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></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="nf">gcd</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">32</span><span class="p">))</span> <span class="c1">// 4
</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://golang.org/pkg/math/big/" title="big - The Go Programming Language"><code>big</code></a><code>.Int.GCD()</code> 関数も<a href="https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95" title="ユークリッドの互除法 - Wikipedia">ユークリッドの互除法</a>の一種で,正の整数 $a$, $b$ に対する最大公約数を $\mathrm{gcd}(a, b)$ とすると</p>
<figure style='margin:0 auto;text-align:center;'>
\[
\mathrm{gcd}(a, b) = ax + by
\]
</figure>
<p>となる $x$, $y$ の組み合わせを探すものだ。</p>
<h2>3つ以上の数の最大公約数</h2>
<p>では3つ以上の数の最大公約数を求めるにはどうすればいいか。
ちょっと考えれば分かるが,たとえば $a$, $b$, $c$ の最大公約数を求めたいなら $\mathrm{gcd}(\mathrm{gcd}(a, b), c)$ とすればいい。</p>
<p>では例題を立ててみよう。
これは「<a href="https://qiita.com/rsky/items/a39070208eaea38394c5">配列の全ての要素の最大公約数を求める</a>」の設問と同等と言える。</p>
<figure>
<blockquote><p><strong>例題2</strong></p>
<p>(290021904, 927964716, 826824516, 817140688) の最大公約数を求めよ。</p>
</blockquote></figure>
<p>まずはベタに for 文を回してベタに解いてみる。</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/big"</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">gcd</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</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">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</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></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">values</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">uint64</span><span class="p">{</span><span class="mi">290021904</span><span class="p">,</span> <span class="mi">927964716</span><span class="p">,</span> <span class="mi">826824516</span><span class="p">,</span> <span class="mi">817140688</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nx">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</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">n</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">values</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="p">=</span> <span class="nf">gcd</span><span class="p">(</span><span class="nx">n</span><span class="p">,</span> <span class="nx">z</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="nx">z</span><span class="p">)</span> <span class="c1">// 92
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>ふむふむ。
イケてそうだな<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。</p>
<h2>Go で関数型プログラミング</h2>
<p>「<a href="https://qiita.com/rsky/items/a39070208eaea38394c5">配列の全ての要素の最大公約数を求める</a>」で紹介されているコードは高階関数(higher-order function)である <code>reduce()</code> による関数型プログラミングになっている。</p>
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>の関数は第一級関数(first-class function)なので関数型っぽいプログラミングも可能なのだが<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, <code>reduce()</code> のような関数は標準では用意されていない。
ただし,似たような機能を持つパッケージを公開しておられる人はいる。
わざわざ自作するのもナニなので今回は以下のパッケージを利用させてもらおう。</p>
<ul>
<li><a href="https://github.com/robpike/filter">robpike/filter: Simple apply/filter/reduce package.</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">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"math/big"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/robpike/filter"</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">gcd</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</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">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</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></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">values</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">uint64</span><span class="p">{</span><span class="mi">290021904</span><span class="p">,</span> <span class="mi">927964716</span><span class="p">,</span> <span class="mi">826824516</span><span class="p">,</span> <span class="mi">817140688</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</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">filter</span><span class="p">.</span><span class="nf">Reduce</span><span class="p">(</span><span class="nx">values</span><span class="p">,</span> <span class="nx">gcd</span><span class="p">,</span> <span class="mi">1</span><span class="p">).(</span><span class="kt">uint64</span><span class="p">))</span> <span class="c1">// 92
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>もしくは <code>gcd()</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/big"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/robpike/filter"</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">values</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">uint64</span><span class="p">{</span><span class="mi">290021904</span><span class="p">,</span> <span class="mi">927964716</span><span class="p">,</span> <span class="mi">826824516</span><span class="p">,</span> <span class="mi">817140688</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</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">filter</span><span class="p">.</span><span class="nf">Reduce</span><span class="p">(</span><span class="nx">values</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="kd">func</span><span class="p">(</span><span class="nx">m</span><span class="p">,</span> <span class="nx">n</span> <span class="kt">uint64</span><span class="p">)</span> <span class="kt">uint64</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">x</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">y</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">z</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</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">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">b</span> <span class="o">:=</span> <span class="nb">new</span><span class="p">(</span><span class="nx">big</span><span class="p">.</span><span class="nx">Int</span><span class="p">).</span><span class="nf">SetUint64</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">z</span><span class="p">.</span><span class="nf">GCD</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</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="mi">1</span><span class="p">).(</span><span class="kt">uint64</span><span class="p">))</span> <span class="c1">// 92
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>としてもよい。
ほら,これなら「実質的にワンライナー」と呼べないこともない(笑)</p>
<p><a href="https://github.com/robpike/filter" title="robpike/filter: Simple apply/filter/reduce package."><code>robpike/filter</code></a> パッケージの作者も書いておられるが</p>
<figure lang="en">
<blockquote>
<q>I wanted to see how hard it was to implement this sort of thing in Go, with as nice an API as I could manage. It wasn't hard.<br>
<br>
Having written it a couple of years ago, I haven't had occasion to use it once. Instead, I just use "for" loops.<br>
<br>
You shouldn't use it either.</q>
</blockquote>
<figcaption><div>via <q><a href="https://github.com/robpike/filter">robpike/filter</a></q></div></figcaption>
</figure>
<p><a href="https://github.com/robpike/filter" title="robpike/filter: Simple apply/filter/reduce package."><code>filter</code></a><code>.Reduce()</code> 関数を駆動するコストを考えれば<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> 普通に for 文で回したほうが安上がりだよね。
イマドキっぽく関数型言語の利点をいくつか取り込んでいるとはいえ Haskell のようなガッツリした関数型言語とは役割が異なるので,無理に関数型にこだわらなくてもいいということである。</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://qiita.com/tawatawa/items/408b872a7092be0d7b3c">3つ以上の数の最大公約数と最小公倍数 - Qiita</a></p>
</li>
<li>
<p><a href="https://qiita.com/taksatou@github/items/d721a62158f554b8e399">Goで関数型プログラミング - Qiita</a></p>
</li>
<li>
<p><a href="https://qiita.com/yohhoy/items/d3c12361bb5eed3cbede">Go言語では高階関数よりforループを使え(by Rob Pike氏) - Qiita</a></p>
</li>
<li>
<p><a href="https://qiita.com/hiruberuto/items/26a813ab2b188ca39019">関数型言語のウソとホント - Qiita</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/recursive-call-and-function-table/">再帰呼び出しと関数テーブル</a></p>
</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/B07VPSXF6N?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51jif840ScL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B07VPSXF6N?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">改訂2版 みんなのGo言語</a></dt>
<dd>松木 雅幸 (著), mattn (著), 藤原 俊一郎 (著), 中島 大一 (著), 上田 拓也 (著), 牧 大輔 (著), 鈴木 健太 (著)</dd>
<dd>技術評論社 2019-08-01 (Release 2019-08-01)</dd>
<dd>Kindle版</dd>
<dd>B07VPSXF6N (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">改訂2版の目玉は7章の「データベースの扱い方」が追加されたことだろう。他の章では,大まかな構成は1版と同じだが細かい部分が変わっていて Go 1.12 への言及まであるのには驚いた。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2019-08-12">2019-08-12</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 改訂2版 みんなのGo言語 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00L0PDMJ0?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/4186Q-UqrDL._SL160_.jpg" width="111" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00L0PDMJ0?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガールの秘密ノート/整数で遊ぼう</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2013-12-17 (Release 2014-07-24)</dd>
<dd>Kindle版</dd>
<dd>B00L0PDMJ0 (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"><a href='https://baldanders.info/blog/000670/'>小中学生にお薦め</a>。小学生高学年くらいならギリで理解可能と思われ。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2014-09-26">2014-09-26</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 数学ガールの秘密ノート/整数で遊ぼう -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B00I8AT1CM?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41vT2D6sERL._SL160_.jpg" width="113" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B00I8AT1CM?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">数学ガール/フェルマーの最終定理</a></dt>
<dd>結城 浩 (著)</dd>
<dd>SBクリエイティブ 2008-07-29 (Release 2014-03-12)</dd>
<dd>Kindle版</dd>
<dd>B00I8AT1CM (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="2019-01-13">2019-01-13</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://cakes.mu/series/339" title="数学ガールの秘密ノート|結城浩|cakes(ケイクス)">数学ガールの秘密ノート</a>」に<a href="https://cakes.mu/posts/16292" title="第195回 ユークリッドの互除法(前編)|数学ガールの秘密ノート|結城浩|cakes(ケイクス)">ユークリッドの互除法が出て来る</a>。はやく本にならないかなぁ。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2">
<p>繰り返し処理が1回余分に回っているが $gcd(a, a) = a$ で影響はないのでご容赦。 <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>では if 文や for 文などは関数でも演算子でもない単なる制御<a href="https://text.baldanders.info/golang/operators-and-statements/" title="演算子とステートメント">構文(stateement)</a>であり,直接ロジックにコンパイルされる。これまでの手続き型言語と関数型言語の利点を合わせたような言語は「マルチパラダイム・プログラミング言語(multiparadigm programming language)」などと呼ばれたりする。 Python や Swift といった近頃流行りの言語もマルチパラダイムの流れのひとつである。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:4">
<p><a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>には総称型(Generics)がないため <a href="https://github.com/robpike/filter" title="robpike/filter: Simple apply/filter/reduce package."><code>filter</code></a><code>.Reduce()</code> 関数内部で <a href="https://golang.org/pkg/reflect/" title="reflect - The Go Programming Language"><code>reflect</code></a> パッケージを駆使することになるが,その分はどうしてもパフォーマンスに影響を与えてしまう(参考: <a href="https://text.baldanders.info/remark/2017/03/generics-vs-duck-typing/">きみは Generics がとくいなフレンズなんだね,または「制約は構造を生む」</a>)。しかし <a href="https://golang.org/pkg/reflect/" title="reflect - The Go Programming Language"><code>reflect</code></a> パッケージが悪というわけではなく,たとえば<a href="https://text.baldanders.info/golang/sort/" title="ソートを使う">先日紹介</a>した <a href="https://golang.org/pkg/sort/" title="sort - The Go Programming Language"><code>sort</code></a><code>.Slice()</code> 関数は <a href="https://golang.org/pkg/reflect/" title="reflect - The Go Programming Language"><code>reflect</code></a> パッケージを効果的に使用した例といえる。高階関数は見た目はクールだが,それに惑わされることなく目的に適うコードを選ぶことが重要である。とはいえ,勉強のために <a href="https://golang.org/" title="The Go Programming Language">Go 言語</a>で高階関数を組んでみようというのは悪くないと思う。 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>