Windows環境を整える


今日は、13日の金曜日。だから何だと言われると困っちゃうけど。。
それなら、明日は、おっぱいの日。何言ってるんだ、このすけべ親父!

おっ、piの日。 3.14ですよ。
尤も、近頃はゆとり教育とかで、piを3と教えているそうだから、今月はpiの月
ですと、言えるかも知れない。

はて、piの桁をさっと欲しくなった場合
ruby -e "p Math::PI"
3.14159265358979
が、簡単でいいかな。

でも、もっとマニアックに桁数が欲しくなったら?(ならないって)
手軽に Schemeでしょうかね。なんじゃい、この展開は!
Windowsで手軽にSchemeをするには、やっぱり emacs を入れておきたいね。
探してみると、GNUでも、Windows用にbinaryを提供してるのね。
近頃のリチャード・ストールマンは、歳を取って丸くなったのか、メンテナが
交代したからかは、定かではありませんが、いいことです。
http://www.t.ring.gr.jp/archives/GNU/emacs/windows/emacs-22.3-bin-i386.zip
を、取ってきて、展開後にフォルダー毎、適当な所に置けばOK。
お好みによって、bin/addpm.exe を実行すると、メニューに登録してくれます。
(ここまでやるなら、Pathも登録してくれれば、更に親切なんですけどね)

emacsだけでもいいのですが、DOS窓が使いづらかったら、ckwとnyacusを使う事で
マウスでのコピペが出来たりして、かなり楽になります。
(see-also: http://d.hatena.ne.jp/dann/20080218/p1)
更に、有名な、MinGWとMinSYSで、コンパイル環境が整います。
また、気持ちの悪い、Windows流 $HOMEからおさらばするために、環境変数
HOMEを設定しちゃいましょう。

これで準備は整ったとばかり、emacs を起動してみると、GNUのコマーシャル
メッセージが出てくる。正直うざいです。即戦闘モードに入りたいんです。
%HOME%に、.emacs を置こうよ。
あれ、Windowsって、先頭が'.'で始まるファイルって作れなかったっけ?
裏技があったと思うけど、忘れてしまったので、emacsに作らせちゃえ。
はい、emacsのメニューから、カスタマイズを選んで適当に設定してから
セーブすれば、勝手に作ってくれます。後は、修正するだけですね。

Windows機には、petite(Scheme)を入れてあるので、FreeBSDと同じ使い勝手に
なるように、my-scheme.el を用意しました。

--- my-scheme.el -------------------------------------------------------
(setq scheme-program-name "C:\\app\\petiterun.bat")
(autoload 'scheme-mode "cmuscheme" "Major mode for Scheme." t)
(autoload 'run-scheme "cmuscheme" "Run an inferior Scheme process." t)

(defun scheme-other-window ()
  "Run scheme on other window"
  (interactive)
  (switch-to-buffer-other-window
   (get-buffer-create "*scheme*"))
  (run-scheme scheme-program-name))

(define-key global-map
  "\C-c\C-s" 'scheme-other-window)

(show-paren-mode)
-----------------------------------------------------------------------

petite.exe をいきなり起動すると、動かなかったので、
cd C:\Program Files\Chez Scheme Version 7.4\bin\i3nt
petite.exe
ラップしてます。
ここまでやって、かなりunixっぽく動く環境になりました。

さて、piを任意桁まで表示する例題でしたね。以前、ypsilonのdirを眺めていた
時に、bench/があって、その中にGambitが提供してるサンプルがある事に気が
ついていました。pi.scmも含まれていたような。

早速、走らせてみます。(以下、emacsのセッション画面です)

c:\sakae\bench\gambit-benchmarks>cd C:\Program Files\Chez Scheme Version 7.4\bin\i3nt 

C:\Program Files\Chez Scheme Version 7.4\bin\i3nt>petite.exe
Petite Chez Scheme Version 7.4
Copyright (c) 1985-2007 Cadence Research Systems

> > 

C-c C-l pi.scm を行った直後です。petiteは load とか define をした時に
応答を返さないので、プロンプトが2つ(最初のやつは、起動直後のもの)
表示されてます。

> > (pies 50 500 10)

Error: variable generic< is not bound.
Type (debug) to enter the debugger.
>

pi を 50桁から計算し、後は、10桁きざみで、500桁まで計算させようとした
んですが、どうやら、generic< というのが定義されていないようで、エラーに
なってしまいました。
はて、generic< は、いずこにあるやら? 調べてみると、benchのドライバー
プログラム(run-petite.sh)に、定義されてました。

(define-syntax GENERIC< (syntax-rules () ((_ . lst) (< . lst))))

他にも genericXX と言うのが定義されてましたので、読み込んでおきます。

今度は、うまく行きました。結果は長くなるので省略して、このスクリプトを
読み解いてみます。

(define (pies n m s)
  (if (GENERIC< m n)
      '()
      (let ((bs (pi-brent-salamin n))
            (b2 (pi-borwein2 n))
            (b4 (pi-borwein4 n)))
        (cons (list b2 (GENERIC- bs b2) (GENERIC- b4 b2))
              (pies (GENERIC+ n s) m s)))))

ご丁寧に、3種類の方法で、pi を n桁計算してますね。
そのうちで、一番短いものを上げます。

; Compute pi using the 'brent-salamin' method.
(define (pi-brent-salamin nb-digits)
  (let ((one (GENERICexpt 10 nb-digits)))
    (let loop ((a one)
               (b (square-root (GENERICquotient (square one) 2)))
               (t (GENERICquotient one 4))
               (x 1))
      (if (GENERIC= a b)
          (GENERICquotient (square (GENERIC+ a b)) (GENERIC* 4 t))
          (let ((new-a (GENERICquotient (GENERIC+ a b) 2)))
            (loop new-a
                  (square-root (GENERIC* a b))
                  (GENERIC- t
                            (GENERICquotient
                             (GENERIC* x (square (GENERIC- new-a a)))
                             one))
                  (GENERIC* 2 x)))))))

折角だから、ちょっと動かしてみます。
> (pi-brent-salamin 50)
314159265358979323846264338327950288419716939937453
> (pi-brent-salamin 200)
314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038119

ちなみに、10000桁の計算には
>  (time (set! tmp (pi-brent-salamin 10000)))
(time (set! tmp ...))
    848 collections
    23905 ms elapsed cpu time, including 80 ms collecting
    24610 ms elapsed real time, including 135 ms collecting
    3877273088 bytes allocated, including 3876027960 bytes reclaimed

約25秒かかりました。