Archive for the ‘inc’ Tag

projecteuler7 と 10...または、newLISP の関数 format

 今回の projecteuler は、10001 番目の素数を求めるという問題 72000000 以下の素数の和 を求める 問題 10 の二つ。どちらも素数を探し出すために繰り返し処理を実行するので、まとめました。

(let (i 3 res '(2))
  (while (< (res -1) 2000000)
    (when (= (length (factor i)) 1) (push i res -1))
    (++ i 2))
  (println "The answer of Problem  7 = " (format "%12d" (res 10000)))
  (print "The answer of Problem 10 = ") (apply + (chop res)))

 このスクリプトの動作は、リスト変数 res に予め素数の初期値を 2 入れて置き、3 から二つ置き(奇数だけ)に組込関数 factor を使って、因数分解数が一個のものを素数と判定し、res に追加していきます。最後に見つかった素数 (res -1)2000000 を超えたら while を抜けて、各問題の答えを表示します。
 ++ は組込で、Common Lisp の incf に相当します。ちなみに、++ は整数用で、浮動小数点数には inc を使います。上記スクリプトに inc を使っても動作します。newLISP の方で必要に応じて型変換してくれますから。もちろん、減算用の ––dec もあります。
 printlnprint も組込で、共に引数を評価して表示します(正確にはカレントI/Oデバイスに出力する)。違いは改行出力の有無です。
 また、組込 chop は Common Lisp の butlast に相当します。つまり、リストの最後の要素を取り除いて返します。リストだけでなく、文字列にも使えるのが newLISP 流です(笑)。これを使って、2000000 超の素数を取り除いています。
 残る副題にもなっている組込 format は文字列を整形する書式関数ですが、Common Lisp の書式を大きく異なります。と言うより、C 言語の printf の書式とほぼ同等です。Lisper には馴染めなくとも、私のような C 言語習得者にとっては救いの神です(笑)。注意が必要なのは、newLISP の整数は 64 ビットですが、通常の整数書式は 32 ビット対応である点 と 32 ビット以上の整数を整形するのに必要な 64 ビット用の書式が OS によって異なる点くらいでしょうか。詳しくは、マニュアルの format の項を見てください。
 さて、気になる答えは、

> [cmd]
(let (i 3 res '(2))
  (while (< (res -1) 2000000)
    (when (= (length (factor i)) 1) (push i res -1))
    (++ i 2))
  (println "The answer of Problem  7 = " (format "%12d" (res 10000)))
  (print "The answer of Problem 10 = ") (apply + (chop res)))
[/cmd]
The answer of Problem  7 =       104743
The answer of Problem 10 = 142913828922
> 

 こんな感じ。

 以上、如何でしょうか?

追記:2013/6/9 スクリプト修正、検討途中のスクリプトを入れてしまった、、、(汗)

newLISP のクロージャ。。。または、破壊的関数の副作用

 newLISP でクロージャと言えば、コンテキストを思い浮かべますが、今回はちょっと違います。
 元ネタは、Closures and Contexts の “Stateful functions using self modifying code” から。

 先ずはスクリプトを、

(define (counter (x 1) reset-flag)
  (if-not reset-flag
      (++ 0 x)
    (counter (- x (counter)))))

 スクリプトのメインは、

(++ 0 x)

 です。0x の位置が逆では、と思われるかもしれませんが、ここがミソです。
 実際に動かしてみましょう。

> counter
(lambda ((x 1) reset-flag) 
 (if-not reset-flag 
  (inc 0 x) 
  (counter (- x (counter)))))
> (counter)
1
> (counter)
2
> (counter)
3
> (counter 5)
8
> (counter 0 true)
0
> (counter)
1
> counter
(lambda ((x 1) reset-flag) 
 (if-not reset-flag 
  (inc 1 x) 
  (counter (- x (counter)))))
> 

 予想通りの動作だったでしょうか?
 この動作に、先程の 0x の位置が重要になってきます。
 マニュアルでは、

inc

syntax: (inc place [num])

place の数値を 1.0 か オプションの数値 num 分加算し、結果を返します。inc は、浮動小数点数計算を実行し、渡された整数値を浮動小数点型に変換します。
Increments the number in place by 1.0 or by the optional number num and returns the result. inc performs float arithmetic and converts integer numbers passed into floating point type.<

place は、シンボルか、リスト構造内の位置、式によって返される数値のいずれかです。
place is either a symbol or a place in a list structure holding a
number, or a number returned by an expression.

 となっています。
 ++ ではなく inc ですが、違いは整数用( ++ )か浮動小数点用( inc )かだけです。
 ++inc も破壊的関数で、place の数値に num の数値を加算して、place の数値を置き換えます。
 そのため、上記スクリプトでは、スクリプト自体が書き換えられていく(!)訳です。つまり、破壊的関数の副作用を使ったクロージャ。

 以上、如何でしょうか?