1. ホーム
  2. フラクタル
  3. フォードの円

ここでは、書籍「フラクタル: 混沌と秩序のあいだに生まれる美しい図形 アルケミスト双書」のp.14に掲載されている、フォードの円を描いてみました。なお、今回はファレイ和を用いて描いていますが、デカルトの円定理を用いた描き方もあり、こちらは別記事で紹介したいと思います。

フォードの円

今回作成したフォードの円です。

フォードの円

フォードの円の描き方

フォードの円を描くための原理は結構単純です。

  1. 直線上に、等しい半径の円を2個、互いに接するようにおきます。
  2. これら2つの円と1つの直線で囲まれた隙間に接する円を描きます。
  3. 2の過程で描いた円、2の過程の元の2つの円の内の1つと1つの直線で囲まれた隙間に接する円を描きます。
  4. 3の過程を繰り返すことでフォードの円を描くことができます。

フォードの円の特徴1

フォードの円はすごく面白い特徴を持っています。以下のようにフォードの円の図に対して座標系を取り、図の縦と横の長さが\(1\)となるようにします。

フォードの円の特徴

このとき、最初に描く一番大きな2つの円は、半径が\(\frac{1}{2}\)でその中心座標はそれぞれ\((0,\frac{1}{2})\)、\((1,\frac{1}{2})\)となります。

これらの2つの円に接する直線(ここでは\(x\)軸)で囲まれた隙間に接する円を描くと、この円の半径は\(\frac{1}{8}\)でその中心座標は\((\frac{1}{2},\frac{1}{8})\)となります。

次に、半径\(\frac{1}{2}\)、中心座標\((0,\frac{1}{2})\)の円と半径\(\frac{1}{8}\)、中心座標\((\frac{1}{2},\frac{1}{8})\)の円、そして\(x\)軸で囲まれた隙間に接する円を描くと、この円の半径は\(\frac{1}{18}\)でその中心座標は\((\frac{1}{3},\frac{1}{18})\)となります。一方、半径\(\frac{1}{2}\)、中心座標\((1,\frac{1}{2})\)の円と半径\(\frac{1}{8}\)、中心座標\((\frac{1}{2},\frac{1}{8})\)の円、そして\(x\)軸で囲まれた隙間に接する円を描くと、この円の半径は\(\frac{1}{18}\)でその中心座標は\((\frac{2}{3},\frac{1}{18})\)となります。

これらを繰り返していくと、面白い特徴が見えてきます。各円の中心の\(x\)座標を既約分数\(\frac{p}{q}\)で表すと、円は半径\(\frac{1}{2q^2}\)、中心座標\((\frac{p}{q},\frac{1}{2q^2})\)となることがわかります。

フォードの円の特徴2:ファレイ和

また、下図のように円の中心の\(x\)座標の値でラベルを振って眺めてみると、見えてくるものがあります。互いに接する2つの円の中心の\(x\)座標をそれぞれ\(\frac{p_1}{q_1}\)、\(\frac{p_2}{q_2}\)とすると、それらの円と\(x\)軸とで囲まれた隙間に接する円の中心の\(x\)座標の値は\(\frac{p_1+p_2}{q_1+q_2}\)となります。つまり、分母と分子を単純に足した値が隙間に接する円の中心の\(x\)座標になっています。実際、下図のラベルを見ていくと、\[ \frac{0}{1} \oplus \frac{1}{1} = \frac{1}{2}, \ \ \frac{0}{1} \oplus \frac{1}{2} = \frac{1}{3}, \ \ \frac{1}{2} \oplus \frac{1}{1} = \frac{2}{3}, \ \ \frac{0}{1} \oplus \frac{1}{3} = \frac{1}{4}, \ \ \frac{1}{3} \oplus \frac{1}{2} = \frac{2}{5}, \cdots \]となっていることがわかります。

この分母と分子をそれぞれ足した値を「ファレイ和」と呼び、記号\(\oplus\)で表します。

ファレイ和

ファレイ和というのはすごく面白いですね。小学生のころ、初めて分数の足し算を習ったとき、分母同士、分子同士を単に足し算して間違いだと言われていたのに、それがファレイ和だと正しいんですから。

プログラムコード

フォードの円を描くプログラムコードを載せておきます。

最初に説明したように、今回はファレイ和を使ってプログラムを作りました。つまり、整数\(p\)と\(q\)を与えて、\((\frac{p}{q}, \frac{1}{2q^2})\)を中心とした半径\(\frac{1}{2q^2}\)の円を描いていくという方法です。

ただし、円を描く順番は\(q\)の値が大きい方から描いています。この理由は、たとえば\(p=1,q=2\)の場合と\(p=2,q=4\)の場合は同じ円になるはずですが、\(q\)の値が小さい方から単純に描いていくと、\(p=1,q=2\)の場合は\((\frac{1}{2}, \frac{1}{8})\)を中心とした半径\(\frac{1}{8}\)の円となり、\(p=2,q=4\)の場合は\((\frac{2}{4}, \frac{1}{32})\)を中心とした半径\(\frac{1}{32}\)の円となるので、\(p=1,q=2\)の円の内部に\(p=2,q=4\)の円が描かれてしまうからです。これは\(\frac{p}{q}\)が既約分数になるように調整してやれば回避できるのですが、今回は円を描く順番を\(q\)の値が大きい方から描くことで、\(p=2,q=4\)の円が\(p=1,q=2\)の円で上書きされるようにして簡易的に回避しました。

void setup(){
  size(500,500);
  background(0,0,0);

  float r_max = width / 2.0; // 円の半径の最大値
  float r_min = 1.0; // 円の半径の最小値
  float r = r_max; // 円の半径
  float x;
  stroke(255,255,255); // 円の輪郭は白色
  fill(0,0,0); // 円の内部は黒色
  circle(0.0, r, 2.0*r); // 最初の大きな円(左)
  circle(width, r, 2.0*r); // 最初の大きな円(右)

  // ファレイ和を用いてフォードの円を描いていく
  int max_q = floor(sqrt(r_max / r_min));
  for(int q=max_q; q>1; q--){
    for(int p=1; p<q; p++){
      x = (float)width * p/q;
      r = r_max / pow(q,2);
      circle(x, r, 2.0*r);
      circle(x, width-r, 2.0*r);
    }
  }
}

コメントを残す