#14 ふれてみよう高校数学 離散数学・数論

フィボナッチ数列と黄金比——自然界の数の神秘

フィボナッチ数列

「前の2つを足して次を作る」——これだけの単純なルールから、自然界の至るところに現れる不思議な数列が生まれます。

フィボナッチ数列は次の漸化式で定義されます:

F1=1,F2=1,Fn+1=Fn+Fn1F_1 = 1,\quad F_2 = 1,\quad F_{n+1} = F_n + F_{n-1}

1,1,2,3,5,8,13,21,34,55,89,144,1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, \ldots

「1個のウサギのペアが毎月1ペアずつ増え、生まれたペアは2ヶ月後から繁殖を始める」——13世紀にイタリアの数学者フィボナッチが「ウサギの繁殖」問題として紹介しましたが、この数列はそれ以前からインドの詩律学で研究されていました。


自然界のフィボナッチ

「なぜこんな数列が自然界に現れるのか」——植物が成長するとき、葉や種を最も効率よく並べようとすると、自然とフィボナッチ数が現れます:

  • ひまわりの種の螺旋:34345555(または 55558989)——「時計回りと反時計回りの螺旋の本数がフィボナッチ数」
  • 松ぼっくりのりん片:881313
  • 花びらの枚数:多くの花が 3,5,8,13,213, 5, 8, 13, 21
  • 植物の茎に巻く葉の角度:360°×(11/ϕ)137.5°360° \times (1 - 1/\phi) \approx 137.5°——「この角度で葉を並べると最も重なりが少ない」

黄金比 φ

「隣り合うフィボナッチ数の比は、どこへ向かうのか」——分数の列 11,21,32,53,85,\frac{1}{1}, \frac{2}{1}, \frac{3}{2}, \frac{5}{3}, \frac{8}{5}, \ldots を計算してみると、ある一定の値に近づいていきます。

隣り合うフィボナッチ数の比 Fn+1/FnF_{n+1}/F_nnn \to \infty でどこへ向かうのでしょうか?

比が収束値 ϕ\phi に近づくと仮定すると、Fn+1/FnϕF_{n+1}/F_n \to \phi なので:

Fn+2Fn+1=Fn+1+FnFn+1=1+FnFn+11+1ϕ\frac{F_{n+2}}{F_{n+1}} = \frac{F_{n+1} + F_n}{F_{n+1}} = 1 + \frac{F_n}{F_{n+1}} \to 1 + \frac{1}{\phi}

収束値では ϕ=1+1/ϕ\phi = 1 + 1/\phi、つまり ϕ2=ϕ+1\phi^2 = \phi + 1——「自分自身の逆数に 1 を足すと自分に戻る、不思議な数」:

ϕ2ϕ1=0    ϕ=1+521.61803\phi^2 - \phi - 1 = 0 \implies \phi = \frac{1 + \sqrt{5}}{2} \approx 1.61803\ldots

これが黄金比(golden ratio)ϕ\phi(ファイ)です——古代ギリシャ時代から「最も美しい比」として知られてきた数です。


比の収束を見る

フィボナッチ比の収束グラフ:縦軸が Fₙ₊₁/Fₙ の値、横軸が n。最初は 2, 1.5, 1.667... と上下に揺れているが、n が増えるにつれて黄色の点線(黄金比 φ≈1.618)に吸い込まれるように収束していく。10項目以降はほぼ区別がつかないほど近づく。
var phi, fibs, i, ratio, ox, oy, pw, ph;

phi = (1 + Math.sqrt(5)) / 2;

fibs = [1, 1];
for (i = 2; i < 20; i++) fibs.push(fibs[i-1] + fibs[i-2]);

function loop() {
ctx.clearRect(0, 0, W, H);

ox = 40; oy = 260; pw = W - 80; ph = 200;

// phi reference line
var phiY = oy - ((phi - 1.3) / 0.5) * ph;
ctx.strokeStyle = '#fbbf2455';
ctx.lineWidth = 1;
ctx.setLineDash([5,4]);
ctx.beginPath();
ctx.moveTo(ox, phiY); ctx.lineTo(ox+pw, phiY); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#fbbf24';
ctx.font = '12px monospace';
ctx.textAlign = 'left';
ctx.fillText('φ = ' + phi.toFixed(6), ox+pw+4, phiY+4);

// y axis labels
ctx.fillStyle = '#475569';
ctx.font = '10px monospace';
ctx.textAlign = 'right';
for (var yl = 13; yl <= 18; yl++) {
  var lyv = yl / 10;
  var lyy = oy - ((lyv - 1.3) / 0.5) * ph;
  if (lyy > 40 && lyy < oy) {
    ctx.fillText(lyv.toFixed(1), ox-4, lyy+3);
  }
}

// plot ratios
ctx.strokeStyle = '#60a5fa';
ctx.lineWidth = 2;
ctx.beginPath();
for (i = 1; i < fibs.length - 1; i++) {
  ratio = fibs[i+1] / fibs[i];
  var ratioY = oy - ((ratio - 1.3) / 0.5) * ph;
  var ratioX = ox + (i-1) * (pw / (fibs.length - 3));
  ratioY = Math.max(30, Math.min(oy, ratioY));
  if (i === 1) ctx.moveTo(ratioX, ratioY); else ctx.lineTo(ratioX, ratioY);
  ctx.fillStyle = '#60a5fa';
  ctx.beginPath();
  ctx.arc(ratioX, ratioY, 4, 0, Math.PI*2);
  ctx.fill();

  if (i <= 7) {
    ctx.fillStyle = '#94a3b8';
    ctx.font = '10px monospace';
    ctx.textAlign = 'center';
    ctx.fillText(fibs[i+1]+'/'+fibs[i], ratioX, oy + 16);
  }
  ctx.beginPath();
  if (i > 1) {
    var prevRatio = fibs[i] / fibs[i-1];
    var prevY = oy - ((prevRatio - 1.3) / 0.5) * ph;
    var prevX = ox + (i-2) * (pw / (fibs.length - 3));
    ctx.moveTo(prevX, Math.max(30,Math.min(oy,prevY)));
    ctx.lineTo(ratioX, Math.max(30,Math.min(oy,ratioY)));
  }
  ctx.strokeStyle = '#60a5fa';
  ctx.lineWidth = 2;
  ctx.stroke();
}

ctx.fillStyle = '#e2e8f0';
ctx.font = '14px monospace';
ctx.textAlign = 'left';
ctx.fillText('Fₙ₊₁/Fₙ → φ = (1+√5)/2 ≈ 1.61803', 20, 22);

requestAnimationFrame(loop);
}
loop();

黄金螺旋

「フィボナッチ数を辺の長さとする正方形を並べると、美しい螺旋が現れる」——ノートの隅に 1, 1, 2, 3, 5, 8, 13 の大きさの正方形を並べて、各コーナーを弧でつなぐだけです。

フィボナッチ数を辺の長さとする正方形を並べ、各正方形の弧を連ねると黄金螺旋(対数螺旋)が得られます。

フィボナッチ正方形が1つずつ現れるアニメーション:小さい正方形から始まり、次々と隣に大きな正方形が追加されていく。各数字はその正方形の一辺の長さ(フィボナッチ数)。この正方形の並びがオウムガイの殻や銀河の螺旋腕と同じ形を作る。
var t, fibSeq, i, ox, oy, scale;
t = 0;

fibSeq = [1, 1, 2, 3, 5, 8, 13, 21];

var colors = ['#3b82f6','#8b5cf6','#22c55e','#f97316','#ec4899','#14b8a6','#fbbf24','#f87171'];

function loop() {
ctx.clearRect(0, 0, W, H);
t += 0.012;

var maxFib = fibSeq[fibSeq.length - 1];
scale = Math.min((W-40) / (maxFib * 1.5), (H-40) / (maxFib * 1.0));

// layout squares: start at center, spiral outward
// Positions computed for fib rectangle layout
var rects = [];
var cx = W/2 - fibSeq[6]*scale/2;
var cy = H/2 - fibSeq[5]*scale/2;

// simplified layout: place squares in order
var px = cx + fibSeq[6]*scale, py = cy + fibSeq[5]*scale;
// direction: right, up, left, down
var dirs = [[1,0],[0,-1],[-1,0],[0,1]];
var x = cx + (fibSeq[5]+fibSeq[4])*scale;
var y = cy + fibSeq[5]*scale;
var dirs2 = [
  [cx + fibSeq[5]*scale*1, cy + fibSeq[5]*scale*0, 1, -1, 'right'],
  [cx + fibSeq[5]*scale*1, cy - fibSeq[4]*scale, -1, -1, 'up'],
  [cx - fibSeq[3]*scale, cy - fibSeq[4]*scale, -1, 1, 'left'],
  [cx - fibSeq[3]*scale, cy + fibSeq[2]*scale, 1, 1, 'down']
];

var squares = [
  { x: cx + fibSeq[5]*scale, y: cy, w: fibSeq[6]*scale, arcStartAngle: -Math.PI/2, arcDir: -1 },
  { x: cx + fibSeq[5]*scale - fibSeq[5]*scale, y: cy - fibSeq[5]*scale, w: fibSeq[5]*scale, arcStartAngle: 0, arcDir: -1 },
  { x: cx - fibSeq[4]*scale, y: cy - fibSeq[5]*scale + fibSeq[4]*scale, w: fibSeq[4]*scale, arcStartAngle: Math.PI/2, arcDir: -1 },
  { x: cx, y: cy + fibSeq[2]*scale, w: fibSeq[3]*scale, arcStartAngle: Math.PI, arcDir: -1 },
  { x: cx + fibSeq[2]*scale, y: cy, w: fibSeq[2]*scale, arcStartAngle: -Math.PI/2, arcDir: -1 },
  { x: cx + fibSeq[2]*scale, y: cy + fibSeq[0]*scale, w: fibSeq[1]*scale, arcStartAngle: Math.PI, arcDir: -1 },
  { x: cx + fibSeq[2]*scale + fibSeq[1]*scale, y: cy + fibSeq[0]*scale, w: fibSeq[0]*scale, arcStartAngle: Math.PI/2, arcDir: -1 },
  { x: cx + fibSeq[2]*scale, y: cy, w: fibSeq[0]*scale, arcStartAngle: 0, arcDir: -1 }
];

var numVisible = Math.min(fibSeq.length, Math.floor(t * 1.2) + 1);

for (i = 0; i < numVisible; i++) {
  var sq = squares[i % squares.length];
  var ww = fibSeq[i] * scale;
  var col = colors[i % colors.length];
  ctx.fillStyle = col + '33';
  ctx.strokeStyle = col;
  ctx.lineWidth = 1.5;
  ctx.fillRect(sq.x, sq.y, sq.w, sq.w);
  ctx.strokeRect(sq.x, sq.y, sq.w, sq.w);
  ctx.fillStyle = col;
  ctx.font = Math.max(8, sq.w/3) + 'px monospace';
  ctx.textAlign = 'center';
  if (sq.w > 12) ctx.fillText(fibSeq[i], sq.x + sq.w/2, sq.y + sq.w/2 + 4);
}

ctx.fillStyle = '#e2e8f0';
ctx.font = '13px monospace';
ctx.textAlign = 'left';
ctx.fillText('フィボナッチ: ' + fibSeq.slice(0, numVisible).join(', '), 14, 22);
ctx.fillStyle = '#fbbf24';
ctx.fillText('φ = (1+√5)/2 ≈ 1.61803', 14, 40);

if (t > fibSeq.length / 1.2 + 1) t = 0;

requestAnimationFrame(loop);
}
loop();

ビネの公式(閉形式)

「漸化式を1項ずつ計算しなくても、nn 番目の値を直接求められる」——これがビネの公式です:

Fn=ϕnψn5F_n = \frac{\phi^n - \psi^n}{\sqrt{5}}

ここで ϕ=1+521.618\phi = \dfrac{1+\sqrt{5}}{2} \approx 1.618(黄金比)、ψ=1520.618\psi = \dfrac{1-\sqrt{5}}{2} \approx -0.618

ψ<1|\psi| < 1 なので ψn0\psi^n \to 0nn \to \infty)のとき:

Fnϕn5(最も近い整数に丸める)F_n \approx \frac{\phi^n}{\sqrt{5}} \quad \text{(最も近い整数に丸める)}

n=10n = 10F10=ϕ10/555.0055F_{10} = \phi^{10}/\sqrt{5} \approx 55.00 \approx 55 ✓——「黄金比を10乗して 5\sqrt{5} で割るだけで10番目の値が求まる」。

導出:行列 (1110)\begin{pmatrix}1&1\\1&0\end{pmatrix} の固有値が ϕ,ψ\phi, \psi であることから導ける(前回の固有値の応用!)——「行列の対角化がフィボナッチの閉形式を生む」。


フィボナッチ数列の恒等式

「フィボナッチ数には美しい関係式がたくさんある」——これらは数学的帰納法や行列の積を使って証明できます:

名前
カッシーニの等式Fn+1Fn1Fn2=(1)nF_{n+1}F_{n-1} - F_n^2 = (-1)^n
ザック条件gcd(Fm,Fn)=Fgcd(m,n)\gcd(F_m, F_n) = F_{\gcd(m,n)}
和の公式k=1nFk=Fn+21\sum_{k=1}^n F_k = F_{n+2} - 1
二乗の和k=1nFk2=FnFn+1\sum_{k=1}^n F_k^2 = F_n F_{n+1}

まとめ

  • フィボナッチ数列Fn+1=Fn+Fn1F_{n+1} = F_n + F_{n-1}1,1,2,3,5,8,13,1, 1, 2, 3, 5, 8, 13, \ldots——「前の2項を足して次の項を作る」
  • 黄金比ϕ=(1+5)/21.618\phi = (1+\sqrt5)/2 \approx 1.618ϕ2=ϕ+1\phi^2 = \phi + 1 を満たす——「自分の逆数に1を足すと自分になる」
  • 隣接比 Fn+1/FnϕF_{n+1}/F_n \to \phi——「フィボナッチ数の比は黄金比に収束する」
  • ビネの公式Fn=(ϕnψn)/5F_n = (\phi^n - \psi^n)/\sqrt5(固有値分解から導出)——「1項ずつ計算しなくても直接求まる」
  • 自然界・芸術・建築に広く現れる「美しい比」——「ひまわりからオウムガイまで」

次回はシリーズ最終回——グラフ理論の基本。頂点と辺で構成される構造の数学を学びます。