Bluepostech

まじめなことを書きます

九九を覚えるだけで全ての小数のかけ算ができる理由

はじめに

九九は小学校2年生で学ぶ算数最初の難関である。誰もが何度も暗唱したり、紙に書いたり、はたまた歌に合わせたり、苦労して九九を覚える。10以上の数や小数のかけ算になると、九九ほど何かを覚えるわけでもなく、筆算やらそろばんで任意の小数のかけ算ができるようになる。人力では手に負えない計算も電卓がやってくれるし、膨大な回数のかけ算と足し算をコンピュータがやって現代社会は回っている。

ところで、ふと疑問に思ったことはないだろうか。

たった9\times9=81個の計算を覚えるだけで、どうして無限にある小数のかけ算が可能になるのだろうか。

思えば、義務教育では「筆算のやり方」は教わるけれども、その根拠はあまりはっきり教えてもらえない。0.001から1億くらいまでのかけ算は教わるけども、その範囲を外れてかけ算ができるのかはわからない。でも九九とその他諸々を覚えれば計算はできるし社会はそうして回っている。なぜなのだろうか。

注:この記事では「有限小数で表すことのできる数」を小数と呼び、その範囲で話をします。つまり分数や無理数の話はしません。

そもそも「小数」って何よ

かけ算の話をするには、まず「数字って何」という話をしなければならない。

数とは我々が勝手に考えた概念だが、「何を満たせば数だ」と決めることができるだろうか。数の具体例を挙げて考えてみよう。 1、77、269、3.14、8.10、11.4514、... といくつか考えてみたが、どうやら以下のことが言えれば小数と言えそうである。 「0、1、2、3、4、5、6、7、8、9の9つの記号を並べたものである。」 この「並べる」というところをもう少し見てみよう。77は  7\times 10+7\times 10^{0}だ。3.14は高校で学ぶ負の指数 0.1=10^{-1}を用いれば 3\times 10^{0}+1\times 10^{-1}+4\times 10^{-2}だ。この「10」というものの中身には立ち入らないことにして、次のように決めればすべての小数を表現できそうだ。

定義1
小数とは、次のように表現できる数のことを言う。
{ \displaystyle
x=a_0 \times 10^0 + a_1 \times 10^1 + a_{-1} \times 10^{-1} +\cdots \\\\
=\sum a_i \times 10^{i}}

ただしa_iは0から9までのいずれかの数字である。二行目は高校数学で出てくる総和の記号だが、簡単に言うと「何かの数字を10の何乗かして足して、を繰り返したもの」ということだ。

このような xの集まりを大学以上の数学の言葉で言うと、集合\{0,1,2,3,4,5,6,7,8,9\}上で集合 \{10^{i} \} を基底とするベクトル空間といい*1、ベクトル空間に属するものをベクトルと呼ぶ。高校数学ではベクトルと言えば矢印だが、それは厳密には幾何ベクトルというものでベクトルの一種である。

ここでは「 \times」という記号を使っているが、今は「数字と10^{i}を結びつける記号」という意味しかない。

10進法では九九だけ覚えればよい

ここで、数321=3\times 10^{2} +2\times 10+ 14857=4\times 10^{3} +8 \times 10^{2} + 5\times 10 + 7のかけ算を考えてみよう。

ベクトルは「ベクトル空間の公理」というものを満たす。公理というと何やら難しそうだが、言ってることは実はざっくり言えば「小学校で学ぶ交換法則、結合法則、分配法則が成り立つ」ということと「0、1に相当するものがある」といったものだ。

ベクトル同士のかけ算は内積というのだが、ここではかけ算のことである。内積についても分配法則は成り立つ。321と4857のかけ算を計算してみよう。

 321 \cdot 4857 = (3\times 10^{2} +2\times 10+ 1\times 10^{0})\cdot (4\times 10^{3} +8 \times 10^{2} + 5\times 10 + 7\times 10^{0}) \\
=(3\times 10^{2})\cdot (4\times 10^{3}) + \cdots +(1\times 10^{0}) \cdot (7\times 10^{0}) \\
=(3\cdot 4) \times ( 10^{2}\cdot 10^{3}) + \cdots + (1\cdot 7) \times (10^{0} \cdot 10^{0})

ここで交換法則と分配法則、結合法則を用いている。

これを x=a_0 \times 10^{0} + a_1 \times 10^{1} + a_{-1} \times 10^{-1} +\cdots の形に書き直せれば、定義1を使って計算を終えることができる。そこでこれと最後の行の式を見比べてみると

  • 3\cdot 4, 1\cdot 7, \cdotsのように数字同士のかけ算を数字にする
  • 10^{3} \cdot 10^{4}, \cdots のように10^{i}同士のかけ算を10^{k}にする

の二つの決まりが決まればよいということがわかる。後者は単に指数法則から 10^{i} \cdot 10^{j} = 10^{i+j} とすればよい。

ここまで来たらわかるだろう。そう、前者こそがまさに「九九」なのである*2。実際には繰り上がりがあるので足し算の九九も決める必要があるが、ここに足し算、かけ算の九九と指数法則があれば任意の小数のかけ算は実行可能であることが示された。

ところで:なんで「九九」なのか

ここまで10進数の話をしてきた。世の中には10以外の進法もある。

たとえば、コンピュータは2進数を使っている。この場合は小数の表し方はこうなる。

{ \displaystyle
x=a_0 \times 2^{0} + a_1 \times 2^{1} + a_{-1} \times 2^{-1} +\cdots \\
=\sum a_i \times 2^{i}}

ここではa_i\{0,1\}の2つしかない。つまり足し算とかけ算のそれぞれで(0\cdot 0),    (0\cdot1), (1\cdot 0), (1\cdot 1)の4通りの結果を覚えればよい。九九を覚えるのが嫌な小学生はコンピュータになればいいのかも知れない。

一般にn進法ではn^{2}通りの結果を覚えればよい。我々の祖先が10進法を採用したことはラッキーなのかも知れないし、アンラッキーなのかも知れない。10というのは人間の演算能力が決めたのだろうか。

追記:冷静に考えたら「人間の手の指が合わせて10本だから」だった。つまり人類の手の指の本数によっては8進数や12進数になっていた可能性もある。

補足:スカラー倍と内積について

厳密には、ベクトルでかけ算に相当するものは「スカラー倍」と「内積」がある。

ベクトル空間では足し算とスカラー倍について交換法則や分配法則が成り立つと定義していて内積が存在するかは触れていない。一方、内積とは、ベクトル同士の二項演算で交換法則、双線形性などを満たすものとして定義される。

つまりスカラー倍と内積は別の概念で、この記事ではスカラー倍に該当するものを\times内積に該当するものを\cdotと一応使い分けている。この記事でスカラーの集合に対応するものは\{0,1,2,3,4,5,6,7,8,9\}で、基底が \{10^{i} \}である。

*1:線形空間」などともいいます。

*2:正確には九九に0の段を足したもの。

このご時世にfortranを触ってきて思ったこと

注意:かなり個人的な愚痴がメインです。

fortranという言語をめぐる現状

fortranという言語を考えてみる

最初に言っておくが、fortranは決して「どうしようもなく使えない過去の遺物」というわけではない。並列計算ライブラリであるMPIやopenMPはCやfortranでの使用をデフォルトとしているし、理論シミュレーション業界ではfortranはCと並んでデファクトスタンダードであり続けている。Cのポインタ機能は初心者にはあまりに強すぎてしばしばセグフォで学習意欲をそいでしまうのに対して、fortranではそのようなことも少ない*1。コードの見栄えもセミコロンが必要なCより見やすい。

ただし、歴史の古いfortranという言語が情報化社会と呼ばれて久しい現代ではそれだけでは不十分であることも確かだ。何百本もの真空管からなるコンピュータをパンチカードで動かしていた時代からありつづけるfortranという言語が、複数のCPUやGPUを持つコンピュータを誰もが持つようになった現代でそのまま通用するわけがない。

もちろんfortranという言語も、モジュールプログラミングやオブジェクト指向といった新しい機能を取り入れてFORTRAN77からfortran2008へと進化してきた。しかしfortranが指向しているのは、fortranが生まれた時代にコンピュータが期待された唯一の役割である「数値計算」だけだ。

それに対して現代はどうだろうか。ありとあらゆる仕事がコンピュータに任されるようになり、マルチメディア処理のようにコンピュータ自身が生み出した分野もある。はっきり言ってしまうとfortranという言語はそういった処理がほとんどできないかきわめて煩雑な手続きが必要になる。

fortranのみで「プログラミング経験あり」と言うと笑われる

ここからは僕の実経験の話だ。

僕は大学に入ってからプログラミングを始めた。物理系の1回生のときに講義で初めてFORTRAN(全部大文字で固定形式でコメントアウトをcでやるやつ!)に触れたのが初めだった。2回生では違う先生が担当してfortran(幸いなことに小文字になって自由形式になった)を学んだ。

僕の親戚には情報系の職業についている人が複数いる。親戚同士の集まりで大学の講義でプログラミングをやっているという話題になって、言語でfortranをやっていることを言うと、こう言われた。

fortranなんかやってんの?今時COBOLのほうがまだ役に立つぞ。

今でも、全くその通りだと思う。COBOLも歴史が古いが、幸か不幸かいまだにCOBOLが基幹システムに使われたまま更新されていない例もあって、そういう意味では需要がある言語ではある。それに対してfortranは研究にしかほぼ使われない。そもそもCOBOLfortranよりもやるべき言語はたくさんある。

言われたとき、別に衝撃を受けたとかそういうわけではなく、「やっぱりそうか」としか思わなかった。というのも自分でもある程度授業以外でもfortranを触ってみたが、どうもピンとこないのだ。同時期に触っていたVBAでは家計簿をまとめるマクロを実装することができてすごいとなったのに、当時はfortranでは何も成果物ができなった。

非情報系にはモダンなプログラミングを教えれる人がいない

それなのに、現代の大学ではなぜいまだにfortranが教えられているのか。答えは単純だ。教えられる人間がいないのだ

情報系にはプログラミングができる人が集まる。当然だ。物理系には物理ができる人が集まる。それも当然だ。だから、物理系にはプログラミングができる人がいるとは限らない。

物理系の人はプログラミングを「道具だ」と言う。その上「道具」はとりあえず使えればそれでよいと考えている人が多い。たとえその道具や使い方が30年以上前の手法であっても、だ。

先に述べた通り、fortranオブジェクト指向のような新たな手法を取り入れながら進化を続けている。しかしモジュールプログラミングもオブジェクト指向も実行速度が劇的に上がったり何か新たな計算ができるようになるわけではない*2。使えればいい人にとっては性能が上がるわけでもないことをわざわざ勉強しようと思わない。

しかも物理系にいる人は物理がやりたい人で、プログラミングがやりたい人ではない。中には機械音痴で仕方なくプログラミングをやってる人もいる。そんな人が手続き型プログラミングをやっとこさ覚えて、それがちゃんと動くのに、大して性能が上がるわけでもない機能をわざわざ覚えようとするわけがない。無論そのような人間は情報系では淘汰される。しかしここは物理系だ。物理で功績を上げれば地位につける。それ自体は当たり前すぎることだ。

結果、物理系では教員でも、たとえばオブジェクト指向が何なのかよくわかっていない人が多い。そのような人が片手間でプログラミングの講義を持つのだから、内容も半期かけてやっと手続き型言語をやって、余った時間は重箱の隅をつつくような、自分で書いていくうちに調べればいいようなことに終始する。そんな人が、もし「プログラミングできます」と言って本当のプロの前に出て行ったらどうなるか、想像に難くない。

もちろん、手続き型プログラミングの経験も重要だ。オブジェクト指向型プログラムも結局手続き型で書いたメソッドやら関数の寄せ集めだから、手続き型プログラミングはその基礎となる。ただし基礎練ばかりしていても試合には勝てない。

fortranを学んだ学生がやるべきこと

ここまで、fortranをやっても不十分だということをつらつらと書いてきた。それで「ここまでfortranをやってきたんだけど、どうすればいいんだ」という人もいるかもしれない。

答えは簡単だ。「fortran以外もやってみる」だけだ。

「文法が簡単だから」というのも講義でfortranが使われる建前の一つになっている。しかし、世の中fortranと同じくらいかそれより簡単な言語もたくさんある。それにループや条件分岐といった基本的な構造はほとんどのプログラミング言語に共通だ。プログラミングをやるために入れた仮想端末やターミナルも、Emacsvimも他の言語でも多くの場合そのまま使える。

fortranでは思っていた成果物が作れずがっかりした」という人もいるかもしれない。fortranは味気ない数値計算しかできないのだからそれも当然だ。windowsで別ウィンドウでなんかかっこいいのを出したいならC#だし、Androidアプリを作りたいならJavaだ。プログラミング言語にはこんな風に用途に応じた使い分けがある。そういう意味でも、いろいろできるようになりたいならいろいろ手を出さないといけない。Pythonなんていうやろうと思ったら何でもできるくらいライブラリがある言語もある。

それでもインストールするのが面倒くさいというのもあるかもしれない。どれだけ経験を積んでも環境構築は面倒なものだ。そういう人でもLinuxを立ち上げればシェルスクリプトはすぐに使えるし、ExcelでAlt + F11でVBAがすぐ使えるようになる。そういう入口から入っても構わない。

大事なのは、「比べる」ということだ。基本的な事項という意味でfortranで学んだものが他の言語に生きるだろうし、逆に他の言語で学んだものがfortranで生きることもあるかもしれない。実際、オブジェクト指向の概念はfortranにもあるがPythonのほうが分かりやすい。そうすることでfortranでは気づかなかったプログラミングの面白さや、fortranの他の言語と比べてもよいところにも気づけるかもしれない。

まとめ

結論として、「プログラミングをやるならfortranだけじゃダメだ」ということだ。

「俺はプログラミングに関わるつもりがないんだ」というなら別にそれでもいい。でもわざわざこのページにアクセスして、しかもおっさんの愚痴みたいな駄文をここまで読んだ人は、そうではないだろうと思う。この先fortranしかいじる予定がないとしても、別の言語もやってみるべきだ。その経験はきっと役に立つ。

*1:ただしfortranでもセグフォが出ることはあるが、fortranでポインタを使うことは少ないのでポインタ由来のセグフォは意図して起こそうとしない限りほぼ起こらない。

*2:僕は試していないのだが、実は実行速度も上がるのかもしれない。ただし革命的によくなるわけでもない。