プログラムを書くということ

の専門は計算機数論である. 計算機を使うということはプログラムを書かなくてはならない. 現任校ではアルゴリズムの講義・演習としてC言語を教えているし, 研究室の大学院生さんには修士論文研究の中で何かプログラムを書いてデータをとり, 検証する訓練をしてもらっている. これまでいろいろな場面で感じたことは, プログラムの組み方は十人十色ということである. たまに「どうやったら良いプログラムをかけるようになるのか」という質問を受けるので, ここでは少しそのことについて書いてみたい. もちろん以下は個人の見解であり, 一般的な答えではないことを断っておく.

いきなり結論かつ元も子もないことを書くが, 上の問いに対する答えは「人のプログラムをたくさん読んで, ひたすら自分の手を動かしてたくさんプログラムを書け」である. 学問に王道なし, という言葉はプログラミングにおいても同じである.

もう少しつけ加えると「汚くてもいいからとりあえず書け」である. 最初から洗練されたプログラムを書こうと思ってはいけない(こう考えていると1行も書けない). 数学でも同じで, 一部の天才・秀才を除けばいきなり完璧な証明を書こうと思っても何も書けないはずである. とにかく愚直に, 正しいと判断できる証明をした後に「ここは余計だったな」「ここは別の方法が使えるな」といった整形をして, よりよい証明に近づける. 教科書レベルから始まって, 参考書などでトレーニングをしていくにつれて「これはこれが最適解」というノウハウが身に付く. これはプログラミングでも全く同じである.

ここで1つ例を挙げよう. 以下はC言語の演習で毎年出題している課題の1つである. プログラムが苦手な方は(そのような方はそもそもこの記事を読んでいないと思うが)少し読み飛ばしてもらって構わない.

double *A;
A=(double *)malloc(sizeof(double)*N*N);
A[i*N+j];

これは2次元配列(数学におけるN次正方行列)をC言語で定義するプログラムである. 実は昔のC言語では多次元配列を直感的に書けないものがあり, なんとか工夫して書かざるを得なかった. このアイデアは単純で, タテ成分とヨコ成分を区別せず, N^2 の長さの1次元配列だと思ってデータを格納する手法である. 同様にして3次元以上の配列でも定義することが可能である. これと同じ実行を与えるプログラムをもう1つ紹介する.

double **A;
A=(double **)malloc(sizeof(double *)*N);
for(i=0; i<N; i++){
    A[i]=(double *)malloc(sizeof(double)*N);
}

これは「多重間接参照」とよばれる, ポインタ技法に関するプログラムである. 1つ目もポインタを使っており, 結局やっていることは同じだが, メモリへの連続アクセス性(データを最適に読み書きする機構)を備えているという意味で優れたプログラムである. また各要素が比較的長いデータ列であるような多次元(とくに3次元以上の)配列を用いたいときに有用である例えば今回の例のように, 文字列の多次元配列を直感的に扱える). ちなみに現在ではこのようなことはしなくても

A[j][i];

のように直感的に配列を扱うことが可能である(添え字がひっくり返っているのはC言語の配列処理の定義による). もっと直感的に使いたい場合は, Magma や Sage といった数式処理システムを使わせてもらえば

A[i][j];

のように書くことができる.

何か計算をさせようとする際に「C言語で書くべき」のような意見を耳にすることがあるが, 個人的には否定的であり, 便利なツールはどんどん使わせてもらえばよい(し効率的である)と思う. もちろんブラックボックス=本当にその計算が正しいかどうかが判定できないという問題には注意しなければならず, そのためには十分な数学力が必要である. 計算機が扱えることはいろいろな場面でアドバンテージとなるが, 基礎学力・数学力がなければ無意味 である. これは僕の研究室の学生さんにも日々伝えている大切なアドバイスである. 一番怖いのは「自分が組んだプログラムが本当に正しいかどうかを自分で判定できない」ことである.

先のプログラムに戻ろう. 4つのプログラムのうち, まずは後半2つの形でまともなプログラムを書けることを目指す. その後, 最初のプログラムを自力で書けるようになることを目指す(といってもC言語の教科書には載っているので, 普通に勉強していたら目にするはずである). そして慣れたら2つ目のプログラムを理解できることを目指す. これがモデルコースだと思う. 何事もコツコツ積み上げていくことが大切であり, 数学も同じである. 最初から2つ目のプログラムを書ける人はそういないだろうし, それでは本当のプログラミングスキルは身に付かない.

これまで何年もプログラミングの講義を担当し, 自身も研究で使い込んできた身としては, プログラミングの得意・不得意は数学のそれよりも個人差が大きいと感じる. ただし, 苦手と感じていてもあまり気にする必要はないと思う. 自分にとって最も書きやすいと感じるレベルでしっかり習熟することが上達への最適解だと思う.

最後に, この記事のタイトルには反するが, 結局一番大事なことは「基礎の勉強をしっかりしてからプログラミングを勉強しよう」である. 数学科ならば, まずは数学をしっかりやってから, である. 大事なことなので2度言いました.

追伸: では横山はどうやってプログラムを組んでいるのか, と思われるかもしれないので少し述べる. 基本的には「数学的に何を計算するのか・何が必要か」を整理できれば計算可能かどうかはわかるので(共同研究をお引き受けする際はここで判断する), まずアナログに紙へデザインを書き出し, 組めるところから地道に組む. あまりこういうやり方をしている人はいないと思うが, ウンウン唸っているくらいなら片っ端から計算していくのが性に合っている. 総数48コアの相棒たち(計算機)には足を向けて寝られない.

Contact:  s-yokoyama [at] tmu.ac.jp