ページ

2012年1月27日金曜日

Gambit for Mac OSX

Mac OS9の時代にMacGambitというLISP系言語があった。LISPは何だか分からない人も多いだろうが、かつてBASICなる言語が初期のパーコンに搭載されていた事なら知っている人も多いだろう。MacGambitはBASICと同じようなインタープリター系言語で、命令を打ち込めば直接実行もできた。ただ残念ながら、ほぼすべてのLISP処理系言語と同様の欠点があった。それは日本語処理はまずもって不可能だという事だ。それにインタープリター処理系言語の常で、大きな処理をさせてみると速度低下が極端に表面化するのだ。そんな言語だったGambitはどうなっているのだろうと調べてみた。

LISPで検索すると1-2個の処理系がヒットするけれど、Gambit と OSX で検索するとすぐに目的のサイトに辿り着いた。2012年1月現在のバージョンは4.6.3になっている。昔と違ってMac OSX ばかりでなく、Windowsや、さらにiPhoneなどでも実行できるようになっている。ここからdistributionページへ移動してプログラムをダウンロードする。ただし、iPhone用はApp StoreにてGambit REPLで販売されている。OSX用はインテルマック用は更新されているが、G4やG5マック用は2010年で更新が止まっている。とはいえソースコードが公開されているので、一度自分が使っているマシンでコンパイルしてみればいいのだ。

プログラムサイズは7MB程度しかないのでダウンロードはすぐに完了するだろう。ダウンロードしてきたGambcをマックにインストールする。インストール後、アプリケーションフォルダの中をいくら探してもGambitは見つからない。それも当然で/Library/Gambit-C/current/bin/以下にインストールされているからだ。Gambitの起動は/Application/Utilities/Terminalを立ち上げてターミナルから行う。まずgsiと打ち込んでみる。

xxxx$ gsi
Gamibit v4.6.0

>
と表示されるだろう。">"はコマンドプロンプトと呼ばれ、命令を入力して下さい、という合図だ。
もしも、ソースコードをコンパイルしたのならデフォールト状態で gsi は /usr/local/Gambit-C/bin 以下にインストールされるので、パスを追加しなければいくらターミナルから gsi を入力しても反応しない。パスを通すには
export PATH=$PATH:/usr/local/Gambit-C/bin
ターミナルから上記を入力すると gsi が起動するようになる。
なお、これだけではターミナルを起動する度にパスを通さないといけないので、通常「~/.bash_profile」に同じ呪文を書き込んでおく。
vi ~/.bash_profile
として内容に
export PATH=$PATH:/usr/local/Gambit-C/bin
を書き込んだら
:wq!
とすれば~/.bash_profileへの書き込みが完了する。

Gambit が起動できたなら、次のようなプログラムを入力してみよう。
> (define (fact n) (if (< n 2) 1 (* n (fact (- n 1)))))
> (fact 30)
265252859812191058636308480000000
> ,q
この最初の1行はfactという関数を定義している。記述は()で挟んだ中に逆ポーランド記法で入力する。右括弧が閉じられた後、リターンを入力すると実行が開始される。エラーが無ければ無事に結果が表示される。factという関数の定義箇所の意味は、もしもnが2以下ならば結果を1とするが、nが2以上ならn-1を値をfactに代入して戻された結果とnをかけ算する、という事だ。簡単に言えばnの階乗を求める関数だ。
出力された整数の桁数が大きい点に驚かされるかもしれないが、Gambitでは大きな整数(bignum)、有理数(分数)、浮動小数点、複素数の計算がサポートされている。なお入力した式に文法間違いがあった場合にはエラー番号がプロンプトの前に表示される。そのような場合にはCTRL+Dで復帰するか、b+リターンキーで実行のバックトレースができる。

> (+ 4 (/ (* 28 4) (sqrt 25)))
132/5
> (expt 7 12)
13841287201

最初の物は4+ 28*4/(√25)を計算したものだ。出力が分数になっているのがお分かりいただけるだろうか。結果が分数ではなく無理数となるなら、答えは小数点表示になる。
2番目の物は7^12を計算したものだ。

こちらのマニュアルが参考してみて下さい。ただ、個人的にはLISPの文法をほとんど忘れていたので、先のマニュアルは難しすぎて読めなかった。簡単な説明という点では少し内容が古いながらこちらが役に立つ。またチュートリアルとしてはPDFファイルながらこちらが参考になるだろう。Gambitと文法がほとんど同様のSchemeという言語の文法なら、例えばこちらなどが参考になると存じます。変数でも数値変数なら理解し易いでしょうが、アトムだ、リストだとなると取っ付きにくいかもしれません。

直接実行ではなくて適当なサンプルプログラムがないか探してみました。Scheme用の物ならばあるのですが、Gambit用はなかなか見当たりません。何とか探しみたのが以下の物です。

;========ここから==========
(define (pi-brent-salamin-approximate base k) ; k is number of digits

(define base^k (expt base k))

(define (fixed.+ x y)
(+ x y))

(define (fixed.- x y)
(- x y))

(define (fixed.* x y)
(quotient (* x y) base^k))

(define (fixed.square x)
(fixed.* x x))

(define (fixed./ x y)
(quotient (* x base^k) y))

(define (fixed.sqrt x)
(integer-sqrt (* x base^k)))

(define (number->fixed x)
(round (* x base^k)))

(define (fixed->number x)
(/ x base^k))

(let ((one (number->fixed 1)))
(let loop ((a one)
(b (fixed.sqrt (quotient one 2)))
(t (quotient one 4))
(x 1))
(if (= a b)
(quotient (* a a) t)
(let ((new-a (quotient (fixed.+ a b) 2)))
(loop new-a
(integer-sqrt (* a b))
(fixed.- t (* x (fixed.square (fixed.- new-a a))))
(* 2 x)))))))

(define (pi-brent-salamin base k) ; k is number of digits
(let ((n (ceiling (inexact->exact (+ 2 (log k))))))
(quotient (pi-brent-salamin-approximate base (+ k n)) (expt base n))))

(define (main arg)
(let ((k (string->number arg)))
(pretty-print (time (pi-brent-salamin 10 k)))
0))

;=========ここまで==========
以上のプログラムをテキストエディタへコピーして保存します。名称は"pi.scm"とします。そのファイルをデスクトップ上に置いておきます。プログラムはテキスト形式で拡張子は.scmにするのが普通です。プログラムの実行は拡張子を除いた名称を使って以下のようにします。下記の例ではπの値を300桁表示します。計算時間がG5マシンのインタープリターで2msですので、もっと大きな数字でも短時間で計算してくれそうです。なお、入力する桁数は""で囲んだ文字列になっていますのでご注意を。

まず、"pi.scm"と同じディレクトリーに移動します。
xxxx$ cd ~/Desktop
xxxx$ gsi
Gambit v4.6.5

>(load "pi.scm")
>(main "300")
(time (pi-brent-salamin 10 k))
2 ms real time
2 ms cpu time (2 user, 0 system)
1 collection accounting for 1 ms real time (1 user, 0 system)
148768 bytes allocated
no minor faults
no major faults
3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273

0 件のコメント: