Archive for the ‘if’ Tag

newLISP マニュアル v.10.5.6 開発版日本語訳公開

 このバージョンは開発版ですが、ifanaphoric if に変身しています。どういう事かと言うと、if の条件式の結果をシステム変数 $it で参照できるのです。と言うことは拙作 aif が不要に、、、
 冗談はさておき、Lutz 氏に感謝!ますます使いやすくなる newLISP です。
 さて、詳細はマニュアルの日本語訳でどうぞ(笑)。

 newLISP の User Manual and Reference の全訳のリリースです。

newlisp_manual-10506
こちらからダウンロードしてください。

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

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

 以上、如何でしょうか?

projecteuler14...または、再帰か繰り返しか

 projecteuler問題14 は、コラッツの問題から、百万以下で最も長い数列をもたらす数値を求めるもの。
 数値を与えて、コラッツの数列を求める関数は、再帰を使うと簡単に定義できます。

(define (collatz n lst)
  (push n lst -1)
  (if (even? n) (collatz (/ n 2) lst)
      (and (odd? n) (> n 1)) (collatz (++ (* 3 n)) lst)
      lst))

 newLISP の ifcond 的な記述ができるので、楽です(笑)。

> (collatz 13)
(13 40 20 10 5 16 8 4 2 1)
> 

 再帰を使うと見通しはいいですが、難点は速度。
 そこで、newLISP には豊富にある繰り返し関数から while を使って、再度定義してみます。

(define (Collatz n)
  (let (lst (list n))
    (while (> n 1)
      (if (even? n) (setq n (/ n 2)) (setq n (++ (* n 3))))
      (push n lst -1))
    lst))

 この程度なら、再帰と比べて見通しも悪くありませんし、早さは 5 ~ 6 倍違います。

> (Collatz 13)
(13 40 20 10 5 16 8 4 2 1)
> 

 これで、コラッツの数列を求める関数はできました。
 後は、百万回繰り返して、最長のリストを求めるだけ。

> [cmd]
(let (res)
  (for (i 1 1000000)
    (let (x (Collatz i)) (if (> (length x) (length res)) (setq res x))))
  res)
[/cmd]
(837799 2513398 1256699 3770098 1885049 5655148 2827574 1413787 4241362 2120681 6362044 
 3181022 1590511 4771534 2385767 7157302 3578651 10735954 5367977 16103932 8051966 
 :
 :
 4025983 12077950 6038975 18116926 9058463 27175390 13587695 40763086 20381543  911 2734 1367 4102 2051 6154 3077 9232 4616 2308 1154 577 1732 866 433 1300 650 
 325 976 488 244 122 61 184 92 46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1)
> 

 最長の数列の長さは 525 。繰り返し関数 for も newLISP では標準です。
 さて、問題の要求しているのは、数列の最初の数値 837799 だけですから、もう少し工夫して、

> [cmd]
(let (res '(0 0))
  (for (i 1 1000000)
    (let (x (length (Collatz i))) (if (> x (res 1)) (setq res (list i x)))))
  (res 0))
[/cmd]
837799
> 

 こんな感じ。

 以上、如何でしょうか?