Perl6でマンデルブロ集合さんを描く

複素関数論のレポートで「マンデルブロ集合さんを描け」というのがあったので、折角だからとPerl6で書いてみました。当然モジュールなんて有るわけないので、フルスクラッチですね、大した量ではありませんが。コードは以下の通り。

実行結果

少なくともRakudo Star 2011.04で動作しますが、最新版のRakudoではpack関数が実装されてないらしく動かないようです。


今回改めて思ったのですが、Rakudo Star遅過ぎですね…。レポート向けに解像度200x200/判定までの回数:20回で出力したのですが、驚くべきことに3時間40分掛りました。コードを見れば解ると思いますが、これでも計算回数を抑えるのに酷いコードを書いています。古い実装にあれこれ言っても仕方ないのですが、気になったのはオブジェクトの生成と、関数呼び出しのコストの高さです。当初の設計では、座標を渡してマンデルブロ集合に属すかどうかを判定する関数を呼んでいたのですが、ピクセル分呼ぶと酷いことになってしまったのでインライン化しました。また、ループの中で変数を宣言すると死ぬほど時間掛かるので使い回してます。これだけで大分見通しの悪いコードが出来上がりました。あとはIO.writeが非常に遅いです、こればかりはどうしようもありませんが…。


ここまで汚いコード書いてるとPerl6で書いてる意味があるのか怪しくなってきますね…。


あと、ビットマップを出力できるモジュールが見当たらなかったので適当にBitmapクラス作りました。こちらはGitHubに上げましたが…あまりに酷い出来です、こんなのでよければ好きに使ってください。open関数に:binオプション渡すのを忘れてて二時間無駄にしたなんて言えない…。


https://github.com/VienosNotes/p6-Bitmap


使い方は単純で、ファイル名を渡してnewして、画像のサイズを渡してmake_headerした後でprint_headerを呼び、あとは一列分のピクセル情報(青0~255, 緑0~255, 赤0~255, 青, 緑, 赤...)を上から順にBitmap.push_lineに突っ込むだけです。4バイト境界のパディングは必要ありません。正しくない長さを書き込んだり、必要以上に回数呼んだりした場合の動作は保証しません。いや、どんな場合でも何も保証しませんけど。デストラクタの書き方が良く分からなかったので、最後に手動でBitmap.closeを呼んであげてください。


今回ので解ったことは、「Perl6はまだまだ未完成、でも普通に他の言語で出来る事は出来なくもない」ってところですかね。Groovyの本で「もはやGroovyは単なる玩具では無くなった」と言い切っていたのが少し羨ましくもありますが。

    • -

追記

組み込みのpack関数を使わずに、自分でBufオブジェクトを作るようにしたら若干高速に動作するようになりました。関数呼び出しの回数も減りましたし、長大なテンプレートのパースをしないぶん速くなっていると思います。

$!file.write(pack $!template, |@line);
#この部分を以下のように変更

my $buf = Buf.new;
$buf.contents.push(|@line);
$!file.write($buf);