Island Life

2012/07/20

ピアノレッスン55回目

  • Janáček: 1.X.1905
    • M=52。このくらいの速さの方がメロディの表現はしやすいが、主題提示部の6連符がきつい。 第一主題提示の後fffに向かって盛り上がるところ、最初は右手旋律が単音なので旋律だけでクレシェンドをかけるのはきついから、左手で補助する。
  • Kapustin: Op40-8
    • 家ではM=132までいったんだけど、ピアノのタッチの違いで崩壊。M=120まで戻して仕切り直し。 タッチが変わると崩壊するのは、まだ手の記憶に頼ってるからだな。
  • Kapustin: Op40-7
    • 今のところまだこれが一番弾きやすい。

Tag: Piano

2012/07/13

Unbounded spigot algorithm

ふとしたきっかけでπなどの値を「頭から順番に」求めるSpigotアルゴリズムを 見直していたら、「メモリの許す限り順番に値を計算し続ける」アルゴリズムを示した 論文を見つけた。

よくあるspigotアルゴリズムは計算したい桁数を最初に決めてデータ構造を初期化する必要がある。Gaucheのexamples/spigotに入ってるのもそれ。 一方、こちらのアルゴリズムはあらかじめ精度を決めておく必要がない。

論文のコードはHaskellで書かれている。

piとpiLは使っている級数の違い。後者の方が生成が速い。論文には他にもう一種類出ている。

実行例。結果は無限数列で返ってくるので欲しいところまで取れば良い。

*Main> take 100 Main.piL
[3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,9,5,0,2,8,8,4,1,9,7,1,6,9,3,9,9,3,7,5,1,0,5,8,2,0,9,7,4,9,4,4,5,9,2,3,0,7,8,1,6,4,0,6,2,8,6,2,0,8,9,9,8,6,2,8,0,3,4,8,2,5,3,4,2,1,1,7,0,6,7]

遅延評価に大きく依存したコードなので通常のSchemeに直すのは面倒そうだが、 gauche.lazy を使えばわりと素直にGaucheに移植できる。 元コードのパターンマッチ部分を手で展開するのはさすがにしんどかったので ちょっとマクロの手を借りた (define*のところ)。

あと、上の素直なコードだと状態配列がすぐに巨大なbignumになって、多倍長演算の遅い Gaucheには負担なので、可能な限り約分するようにしている (lftのところ)。

pipiL はジェネレータを返すので、こんな感じで結果を取り出せる。

gosh> (generator->list (piL) 100)
(3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8 3 2 7 9 5 0 2 8 8 4 1 9 7 1 6 9 3 9 9 3 7 5 1 0 5 8 2 0 9 7 4 9 4 4 5 9 2 3 0 7 8 1 6 4 0 6 2 8 6 2 0 8 9 9 8 6 2 8 0 3 4 8 2 5 3 4 2 1 1 7 0 6 7)

先頭から次々に、いくらでも桁を取り出せるのは魅力的なんだけれど、 実際に走らせてみると状態配列(lft)の値が(適宜約分しても)どんどん大きくなるので、 実は計算量はO(n^2)とかになってるっぽい。桁数が進むとどんどん遅くなる。 なのでおもしろいけれど実用的ではなさそうだ。

Tags: Gauche, Haskell, Programming

2012/07/12

ピアノレッスン54回目

  • Stravinsky: Tango for piano
    • 自分の思い描く感じで弾けるようになってきた、ような気がする。 細部まできちんと弾くのはまだ難しい。
  • Janáček: 1.X.1905
    • M=48で。リズムキープが難しい。

Tag: Piano

2012/07/11

Clojureの選択

Clojureはなぜ遅いのか、という話

JVM言語同士で比べてもやっぱり遅い。

  • 起動の遅さが際立っている。これはどうも初期化時にdocstringやその他のメタデータをセットアップするのに時間がかかってるらしい。
  • 初期化が終わって実際の処理に入っても遅い。これはimmutableなデータ構造のオーバヘッドらしい。immutableなデータ構造でもアルゴリズムのオーダーをmutableなやつと同じにすることはできるが、定数係数のオーバヘッドはある。

まあ、でもRichはそれは覚悟の上というか、設計上そういう選択 (遅いのはわかってるが 他のメリットを優先) をしたわけだからなあ。比べられる土俵が悪いという気はする。 そうは言っても比べられちゃうのは仕方ないけれど。

Gaucheでは上の2点については速度の方を優先する選択をしている。 util.sparseのsparse vectorはClojureのpersistent vector構造を 参考にしているけどmutableだし、docstringが無い理由のひとつはまさしく 起動時のオーバヘッドを避けるためだ。

どちらの選択も絶対的な良し悪しがあるわけじゃなく、目的によるとしか言えない。

もっともClojureはREPLでなければバッチコンパイルを通せるのだから、 docstringをまとめてひとつのdata領域に押し込めるとかできそうなものだけど、 JVMの制約だったりするんだろうか。ネイティブに落とす感覚だと、 コンパイル時にメタデータをデータ配列に固めちゃって、関数の方にはオフセットを 持たせとけば、実行開始時にデータ配列をmmapするだけなんで一瞬で済むはずだけど。

(Gaucheは静的データに関してはポインタの絶対値を持たせているので、 起動時にld.soがリロケートするオーバヘッドはかかっているはず。こちらは 起動速度と実行速度のトレードオフ。)

Tags: Gauche, Clojure

2012/07/05

ピアノレッスン53回目

  • Kapustin: Op40-8
    • MM=120。指よりも頭が律速になってる感じ。
  • Janáček: 1.X.1905
    • 第一楽章通し。まだゆっくり。妙なアクセントがつかないように気をつける。

Tag: Piano

More entries ...