Archive for 2013年3月24日|Daily archive page
projecteuler...または、newLISP組込関数の紹介
projecteuler.net は Lutz氏が newLISPフォーラムで紹介している、ブログラムで解く数学問題が並ぶ webサイトです。
Lutz氏を始め、色んな人が挑戦しているので、私の出る幕ではありませんが、newLISP 固有の組込関数を紹介する良い機会だと思い、やって見ることに、、、
まっ、どこまで続けられるか、わかりませんけどね(笑)。
さて、早速本題です。
最初の問題1 Multiples of 3 and 5 は 1000 未満の自然数で 3 と 5 の倍数の和を求めるというもの。
newLISP では、こんな感じで求められます。
> (apply + (unique (append (sequence 3 999 3) (sequence 5 999 5)))) 233168
ここで使っている sequence と unique は newLISP 組込関数です。
まず、sequence は、任意の等差数列を生成します。引数は、第一が開始数値、第二が終了数値です。第三はオプションでステップ数値、指定しなければ 1 になります。引数には全て、整数と浮動小数点数が使えます。当然、引数が整数なら整数の数列、引数が浮動小数点数なら浮動小数点数の数列になりますが、第三引数を指定した場合は、全て、浮動小数点数の数列になります。
だから、
(sequence 3 999 3)
は 3 から 999 間の 3 の倍数の数列を生成しますが、数列の数値は整数ではなく、浮動小数点数です。といっても、newLISP は標準で倍精度浮動小数点数ですから、今回の問題を含め、16桁くらいまでは気にする必要はありません。
ちなみに、newLISP の整数も64ビットなので、最大値と最小値は
9,223,372,036,854,775,807 -9,223,372,036,854,775,808
となり、これらを超える整数値が必要な時は注意が必要です。
さて、組込関数 unique は、リスト中の同一の要素を削除してくれます。だから、3の倍数と5の倍数で重複している数値を削除するために使えます。
以上で問題1は終了ですが、ここはちょっと汎用関数を考えてみましょう。
引数に数列と選択する述語を与えて、必要な数列を求める
(select-numbers 数列 述語1 述語2 ...)
こんな感じの関数。具体的には、
(define (select-numbers numbers)
; (select-numbers numbers predicate1 predicate2 ...)
(unique (flat
(let (res '()) (dolist (func (args)) (push (filter func numbers) res -1)))
)))
となります。
動作は、
> (select-numbers (sequence 1 10) even?) (2 4 6 8 10) > (select-numbers (sequence 1 10) odd?) (1 3 5 7 9) > (select-numbers (sequence 1 10) odd? even?) (1 3 5 7 9 2 4 6 8 10)
こんな感じ。
これで、問題1を解くと、
> [cmd] (apply + (select-numbers (sequence 1 999) (fn (x) (if (= (% x 3) 0))) (fn (x) (if (= (% x 5) 0))))) [/cmd] 233168
となり、数列も整数値ですっきり(笑)。
ここで fn も newLISP組込関数で lambda と等価です。
以上、如何でしょうか?