Common Lispに入門したので技術メモを投稿します.Qiita入門も兼ねています.どうぞよしなに(´・ω・`)
#いきさつと概要
吉田武教授が東海大学出版から素数夜曲―女王陛下のLISPなる書籍を出されており,タイトルが気になってLispに入門した次第であります.
吉田武氏はSchemeを扱っておられるようだが,僕は"[Land of Lisp](https://www.oreilly.co.jp/books/9784873115870/"Land of Lisp")"で入門したので,開発環境はCLISP2.49となっております.
ネタは2018年の東京大学入試数学の第2問です.問題文は次の通り.
数列a_1,a_2,\cdotsを
a_n = \dfrac{ {}_{2n+1} C {}_n }{n!} (n = 1,2,\cdots)
で定める.
(1)n \geqq 2とする.\dfrac{a_n}{a_{n-1}}を既約分数\dfrac{q_n}{p_n}で表すとき,分母p_n \geqq 1,分子q_nを求めよ.
(2)a_nが整数となるn \geqq 1を全て求めよ.
(1)は計算するだけ(こんな出題で大丈夫かUT).さて問題は(2)をどう料理するか.出題者の意図的文脈では(1)の誘導に乗ってパリティ(偶奇)で論じろという香りがプンプンしますが,そこは反骨精神を存分に発揮し(Lisper仕草?),狭義単調減少性を示した後に,$a_n$を1より小さくなるまで手計算しました.それでも15分程度で処理できたのでまぁ良しという感じですね.
Common Lispで$a_n$を計算するコードは以下のように実にシンプルなものとなります.
コード
(defun factorial (n)
(if (<= n 1)
1
(* n (factorial (1- n)))))
(defun combination (a b)
(/ (factorial a) (* (factorial b) (factorial (- a b)))))
(defun abc (n)
(/ (combination (+ (* n 2) 1) n) (factorial n)))
たった8行.3ブロックあるので順に説明していきます.
まずは第一ブロックから.
(defun factorial (n)
(if (<= n 1)
1
(* n (factorial (1- n)))))
階乗$n!$(英語ではfactorial)を計算する関数 factorial を定義しました.
このfactorial(n)は引数nに任意の自然数を与えるとn!を瞬時に返してくれます.
Tips
-
if-else処理の構文は(if [条件部] [then節] [else節])
-
(1- は与えられた数値から1を引く演算子のようなもの.
-
(* n (factorial (- n 1)))のように記述しても同様に実行できます.
-
recursive functionの実装美しすぎィ
python3ならmathライブラリにmath.factorial()関数が実装されてるって?やかましいわ!
次いで,第二ブロック.
(defun combination (a b)
(/ (factorial a) (* (factorial b) (factorial (- a b)))))
組み合わせを計算する関数 combination を定義しました.
最後にメインディッシュ,第三ブロック.
(defun abc (n)
(/ (combination (+ (* n 2) 1) n) (factorial n)))
入力nに対して出力$a_n$を返す関数 abc を定義しました.こいつを実行すれば $a_8$の時点で2031/4032となるのが解ります.絶妙な収束速度.
#まとめと言いたいこと
- Lispを使えばint,double,floatなどの型指定なしでサクッと数値計算できるよ
- シンプルな文法で初学者にもとっつきやすいよ(というかむしろ『全ての言語はLispに始まりLispに終わる』ですね.失礼いたしました.)
- gnuplotに投げるとすぐgraph描いてくれるよ(maximaはlispで書かれてるようですね)
参考文献
ISBN | Title | Date of publishing |
---|---|---|
978-4-87311-587-0 | Land of Lisp | 2013/02/23 |
978-4486019244 | 素数夜曲―女王陛下のLISP | 2012/06/01 |