Archive for 2013年3月|Monthly archive page

projecteuler2...または、newLISP リストのインデックス操作

 projecteuler も2回目。
 問題2は 1, 2 から始まるフィボナッチ(Fibonacci)数列で四百万を超えない偶数値の和。
 まずは、フィボナッチ数列を求めます。

> [cmd]
(let (fibo '(1 2))
  (while (< (fibo -1) 4000000)
    (push (apply + (-2 2 fibo)) fibo -1))
 (chop fibo))
[/cmd]
(1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 
 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578)
> 

 こんな感じ。ここで、関数chop は組込関数で Common Lisp の butlast に相当します。つまり、リストの最後の要素を削除するもの。また Common Lisp では自分で定義する必要のある while も newLISP では組込です。動作は、、、説明いりませんね(笑)。
 今回のもう一つの主題、リストのインデックス操作。そのための関数(nthslice)もありますが、インデックス数を使って直接操作するのが newLISP 流(笑)。暗黙のインデックス機能(Implicit indexing)です。
 上記の中では、リストから最後の要素を取り出す

(fibo -1)

 や最後から二つの要素の部分リストを作る

(-2 2 fibo)

 がそれに相当します。
 そして、本題。求めたフィボナッチ数列から偶数を取り出すのに前回の select-numbers を使ってもよいのですが、述語(条件式)が一つですから、ここは newLISP組込filter を使います。この関数は、リストから述語(条件式)で真(true)になるものだけ返します。

> (filter even? (sequence 1 10))
(2 4 6 8 10)
> 

 もちろん、この関数とは逆に、述語(条件式)で真(true)になるものだけリストから削除する関数clean もあります。
 さてと、問題2の解答は、

> [cmd]
(let (fibo '(1 2))
  (while (< (fibo -1) 4000000)
    (push (apply + (-2 2 fibo)) fibo -1))
  (apply + (filter even? (chop fibo))))
[/cmd]
4613732
> 

 となります。
 あっ、述語(条件式)even? も組込です。説明、、、いりませんね(笑)。

 以上、如何でしょうか?

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

 ここで使っている sequenceunique は 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 と等価です。

 以上、如何でしょうか?

newLISP マニュアル・アップデート v.10.4.5 rev 2013-03-14

 newLISP のマニュアルrev 2013-03-14 に変更されました。

 今回の変更は、ちょっとした間違いの修正。指摘されれば気がつくけど、つい見過ごしてしまうようなもの。まっ、私も翻訳中に気が付きませんでしたけどね(汗)。

 newLISP マニュアル & リファレンス の日本語訳、現在のバージョンは v.10.4.5 です。

こちらから newlisp_manual-10405 をダウンロードして下さい。

 目次も含め日本語併記にしてあります。

 いつものように、間違いやおかしな点が有りましたら、こちらの blog までご一報下さい。

 以上、如何でしょうか?

64ビットWindowsで空きメモリを表示してみる...または、拡張 import の使用

 以前、newLISP で空きメモリも表示したことがありますが、32ビットの頃の話。
 Windows8 を 64ビット にしたので、GlobalMemoryStatus では、正常な値が取れません。GlobalMemoryStatusEx を使う必要があります。
 そこで、拡張importstruct の出番です(笑)。

(import  "kernel32.dll" "GlobalMemoryStatusEx" "long" "void*")
(struct 'MEMORYSTATUSEX "long" "long" "long long" "long long" "long long" "long long" "long long" "long long" "long long")
;(setq ptrEx (append "64" (chop (dup "00" (* 8 8)))))
(setq ptrEx (pack MEMORYSTATUSEX '(64 0 0 0 0 0 0 0 0)))

 こんな感じで GlobalMemoryStatusEx を準備します。
 変数ptrEx の先頭に64を設定している理由は、MEMORYSTATUSEXdwLength に説明があります。要するに入れておけということ。GlobalMemoryStatus では必要ないのですが、、、
 こうしておけば、

(GlobalMemoryStatusEx ptrEx)
(unpack MEMORYSTATUSEX ptrEx)

 の実行で、

(64 15 8254586880 6973407232 9529655296 8148525056 2147352576 2128674816 0)

 こんな風に必要なデータがリストで得られます。簡単、簡単(笑)。
 リストの中身はこちらを参照して下さい。
 ちなみに空きメモリは

((unpack MEMORYSTATUSEX ptrEx) 3)

 です。
 以上如何でしょうか。

P.S.
 開発版の newLISP 10.4.7 に 64-bit Windows の記述があります。
 次の安定版で登場するかも。
 まっ、64ビットWindows8 でも 32ビット版newLISP で間に合ってますけどね(笑)。