僕らの研究室

僕らの日常を書きます。

TeXで解く入試数学

2021年、一橋大学の入試で、次のような問題が出題されました。

1000以下の素数は250個以下であることを示せ。

この問題を見た受験生はこう思ったことでしょう。

「1000以下の素数を全部書き出せばいい」

この問題は、たったこれだけのことです。実際に解答を作成すると、次のようになります。

素数の定義さえ知っていれば小学生でも解ける問題です。なぜ天下の一橋大学がこのような問題を出題したのか。理解しがたいですね。


ーーーーーーーーーーーーーーーーーーーーーーーーー


さて、茶番はこのくらいにしておきましょう。

皆さん、TeXはご存知ですよね。僕のブログでは過去に何度も登場していますが、要は数式を含む文書を綺麗に作成するもののことです。

以下、数学科の人などにとっては「そんなの知ってるよ!」という説明がいくらかあると思いますが、どうかお付き合いください。また、専門的な用語が出てくることがありますが、わからない人は読み飛ばしていただいて大丈夫です。

今一度上の画像を貼ります。

問題のタイトルはこの記事のものにしておきました。

画像を見ていただければわかる通り、この解答では1000以下の素数をすべてかき出しています。

「全部打つの大変だったねー」という感想が聞こえてきそうですが、じつはこれ、自分で2,3,5,…と打ち込んでいるわけではないのです。

"TeXは文書を作成するもの"と認識している人は少なくないと思っています。\sumと打てばΣ(シグマ)を出力してくれて、\alphaと打てばα(アルファ)を出力してくれる。このような、直接見た目に変化をもたらすものを扱うことがほとんどです。

しかし、その内部では様々なことを理解し、実行してくれています。例えばカウンター。align環境などは自動で式番号を振ってくれますが、TeXは現在の式番号をきちんと覚えていて、次の番号へいくときにはカウンターを1進めて出力するということを行っています。

また、TeXで作成した文書が美しいのも、TeXが行ごとに並べる文字数を決め、その行の文字と文字の間隔を適切に決めてくれているからです。

わかりやすく言えば、TeXは空気を読んでくれるのです。だから、綺麗な文書が簡単につくれるのです。

というわけで、TeXは立派なプログラミングなのです。もちろん、計算に広く用いられている言語たちに比べると、TeXにできることはないといってもよいほど些細ですが、それでも1000以下の素数を見つけきるくらいのことはできます。

ちなみに10000程度で計算に死ぬほど時間がかかります。あまり無理をさせてはいけません。

さて、少し長くなりましたが、素数を見つけるコマンドのソースを公開します。なお、作成者は僕ではなく保護者くんです。このくだらない記事のために15分ほどかけてつくってくれました。

以下をプリアンブルにかきます。画像が2枚になってしまったのはごめんなさい。

細かい説明は後にしますね。本文は次のようになっています。

question環境やkaitou環境は僕が勝手につくったものなので、このままこれを写してもエラーを吐きます。記事の最後に、PCで閲覧してる人に向けてコピペできる形で自作のパッケージを取り除いたソースを残します。

まあ、誰が使うねんこんなもんって感じですけど。

では、軽く解説していきますね。見る人が見ればわかると思うので、そういった人は読まなくてOKです。

まず大まかに説明します。Aを変数と思って、Aに2から1000まで順に代入していくことを考えます。初めはA=2です。このAに対して、2からA-1までの数で割り切れるかを判定しています。割り切れればAは素数ではないということなので、Aの値を1増やします。2からA-1のどの数でもAを割り切れなければ、Aは素数です。その値を出力して、Aの値を1増やし、次のAに対して同じことを行います。これを1000まで繰り返します。これが、素数を出力しきるアルゴリズムです。

ちなみに、素数を出力するたびに値を1増やすカウンターを用意しているので、「個数は168個である」の部分もそのカウンターの値を出力するだけです。

細かい話をしていきます。素数の間の, (カンマ)は、3以上の素数の直前に出るようになっています。素数を出力してから, を出すようにするには、最後の素数が最後のものであることを取得しなければなりません。そうしないと、上で997の後にも, が出てしまいます。997が1000以下の最後の素数であることを判定するにはそれなりの手間がかかるので、先に, をかいてから数を出力するようにしています。

それから、上では単に「割り切れるかどうかを見る」というふうにかきましたが、TeXには割り切れるかどうかを判断する能力はありません(少なくとも、私は知りません)。しかし、「ある数がある数に等しいかどうかを見る」ということはTeXにもできます。また、レジスタに対して四則演算を施すこともできます。

しかし、これだけでは素数判定はできません。ここで、TeXのある機能を逆手にとります。 これがこのプログラムの肝といってもよいでしょう。

TeXは、カウンターレジスタのような整数値のみをとるレジスタに対して割り算を行ったとき、その計算結果では少数を切り捨てるのです。だから、4を2で割ると2ですが、5を2で割っても2なのです。ということは、割り切れるかどうかは「割るときに使った数を割った結果に掛けて元に戻るかを見ればよい」ということになります。

以上がソースコードの解説になります。


いかがだったでしょうか。後半は読者の大半を置いてけぼりにしてしまったような気がしますが、たまにはこのような記事もよいでしょう。

最後にソースコードを貼っておきますから、興味があれば遊んでみてください。

ではでは!!

※改行がイカれてる可能性があります。適宜空気を読んで直していただければと思います。

\documentclass[dvipdfmx,12pt]{jsarticle} \makeatletter \newif\ifSOSUU \newif\ifTWO \SOSUUtrue \newcount\@tempcntc \newcount\@tempcntd \newcount\@tempcnte \newcommand{\sosuu}[1]{% #1以下の素数は, \TWOtrue \@tempcnta\@ne \@tempcntc\z@ \@whilenum\@tempcnta<#1\relax \do{% \advance\@tempcnta\@ne \@tempcntd\@tempcnta \@tempcntb\@ne \@tempcnte\@tempcnta \advance\@tempcnte-\@ne \@whilenum\@tempcntb<\@tempcnte\relax \do{% \advance\@tempcntb\@ne \divide\@tempcnta\@tempcntb \multiply\@tempcnta\@tempcntb \ifnum\@tempcnta=\@tempcntd\relax \SOSUUfalse \fi \@tempcnta\@tempcntd }% \ifSOSUU \advance\@tempcntc\@ne \ifTWO\TWOfalse\else, \fi \the\@tempcnta \fi \SOSUUtrue }% であり,個数は\the\@tempcntc 個である. } \makeatother %%%%%%%%%%%%%%%%%%%%%%%%%ここから本文%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document} \noindent 【\textbf{\TeX で解く入試数学}】\par 1000以下の素数は250個以下であることを示せ.\par \noindent 【\textbf{解答}】 \sosuu{1000}% これで示せた. \end{document}