はじめに
先日、調べものついでに読まなくなって久しい古雑誌を整理していました。古雑誌の記事は今となってはいささか時代遅れのものがほとんどなんですが、中には今でも十分通用する貴重な資料も少なからずあるので手当たり次第に処分するわけにもいかず、一冊ずつ手にとって目次を確認してたんです。パラパラめくってた一冊に当時(おそらく20年以上前)に書いたであろうコードを打ち出したプリンタ用紙が挟まっていました。BASICで書かれたコードの先頭には10 '--- MANDELBROT-SET ---
とコメントされていて……思い出しました。確かに当時、科学雑誌に掲載されていた数式を頼りにコードを書き、8bit-CPUとBASICインタプリタで実行し、マンデルブロ集合の全体像を描くのに丸一日かかったのを覚えています。今や当時に比べればCPU性能はケタ違い(どころの騒ぎじゃない)ですから、より綺麗なマンデルブロ集合をより速く描けるはずで……。
マンデルブロ集合とは
マンデルブロ集合とは、数学者ブノワ・マンデルブロが見つけた不思議な集合。複素平面上の点の集合なのですが、計算式はとてもシンプル。
複素数 C = x + yi を用意し、
Z0 = 0
Zn+1 = Zn2 + C
で計算されるZnが発散しないとき、複素数平面上の点Cはマンデルブロ集合の要素となります。実数部(X軸):-2.0 ~ 1.0、虚数部(Y軸):-1.5 ~ 1.5 の複素平面上でマンデルブロ集合を図示したのが図1です。
単純な計算式ですが、計算機での作図には少々ゴマカシが用いられます。
ゴマカシのひとつが発散するか否かの判定。「発散する」とは、演算を繰り返すうちに点Znが原点(0+0i)から無限の彼方に遠ざかることですが、計算上はZnの絶対値が2.0を超えた、すなわち実部と虚部の二乗和(norm:ノルム)が4.0を超えた時点で発散を始めたと判断して演算を打ち切ります。とはいえ |Zn| > 2.0 ならば |Zn+1| > |Zn| であることが証明できるので、じつはゴマカシでもなんでもないのですけど。
もうひとつのゴマカシが演算の繰り返し回数です。マンデルブロ集合の定義に従うなら、演算 Z = Z^2 + C を無限に繰り返しても発散しないことを判定しなければならないのですが、無限回繰り返すには無限の時間を要するのでいつまで経っても点ひとつ描くことができません。なので適当な回数繰り返したところで演算を打ち切ることにします。
疑似コードで書けば以下のようになります:
// Cがマンデルブロ集合の要素であれば-1、 // そうでなければ発散開始までの繰り返し回数を返す。 int Calculate(複素数 C) { 複素数 Z = 0; int limit = 繰り返し上限回数; for ( int count = 0; count < limit; ++ ount ) { if ( |Z| > 2.0 ) { return count; // Cはマンデルブロ集合の要素ではない } Z = Z*Z + C; } return -1; // // Cはマンデルブロ集合の要素である }