複素数平面と変換
複素数の乗算 = 幾何変換
「紙の上の図形を、ハサミで切り取ってクルっと回してサイズを変えて貼り直す」——これが複素数の乗算が持つ幾何的な意味です。
前回、複素数の積では「絶対値の積、偏角の和」になることを学びました:
これを幾何的に読み直すと:
複素数 に複素数 を掛けることは、 を原点を中心に角 だけ回転し、 倍に拡大縮小する変換
です——「掛け算一発で回転と拡大縮小が同時に実現できる」のが複素数の強みです。
特別な乗数
「どの複素数を掛けると何が起きるか」——代表的なパターンを覚えておきましょう:
| 乗数 | 効果 |
|---|---|
| 回転(反時計回り) | |
| 回転(点対称) | |
| 回転(または ) | |
| の回転(大きさ変わらず) | |
| (実数) | 倍の拡大縮小(回転なし) |
| 回転 + 倍拡大縮小 |
例
「 を掛けると 90° 回転する」——具体例で確認しましょう。
に を掛けると:
:確かに 回転しています——「右上にあった点が左上に移動」しました。
インタラクティブ図解:複素数変換
マウスを左右に動かすと乗数 の偏角が変わり、点群が回転します。マウスを上下に動かすと絶対値(スケール)が変わります。
var OX = 300, OY = 190, SC = 55;
// 図形の点(文字 'F' に似た形)
var shape = [
[0,0],[1.5,0],[1.5,0.3],[0.3,0.3],[0.3,0.8],[1.2,0.8],[1.2,1.1],
[0.3,1.1],[0.3,1.8],[1.5,1.8],[1.5,2.1],[0,2.1]
];
function mulC(re, im, wr, wi) {
return [re*wr - im*wi, re*wi + im*wr];
}
function toS(re, im) { return [OX + re*SC, OY - im*SC]; }
function loop() {
ctx.clearRect(0, 0, W, H);
// w の偏角と絶対値
var phi = ((mx / W) * 2 - 1) * Math.PI; // -π to π
var scale = 0.3 + (1 - my/H) * 1.7; // 0.3 to 2.0
if (scale < 0.3) scale = 0.3;
var wr = scale * Math.cos(phi);
var wi = scale * Math.sin(phi);
// グリッド
ctx.strokeStyle = '#161b22'; ctx.lineWidth = 1;
for (var gx=-5;gx<=5;gx++){ctx.beginPath();ctx.moveTo(OX+gx*SC,0);ctx.lineTo(OX+gx*SC,H);ctx.stroke();}
for (var gy=-3;gy<=4;gy++){ctx.beginPath();ctx.moveTo(0,OY-gy*SC);ctx.lineTo(W,OY-gy*SC);ctx.stroke();}
ctx.strokeStyle='#30363d';ctx.lineWidth=1.5;
ctx.beginPath();ctx.moveTo(0,OY);ctx.lineTo(W,OY);ctx.stroke();
ctx.beginPath();ctx.moveTo(OX,0);ctx.lineTo(OX,H);ctx.stroke();
ctx.fillStyle='#8b949e';ctx.font='12px sans-serif';
ctx.fillText('Re',W-24,OY-8);ctx.fillText('Im',OX+8,14);
// 単位円
ctx.beginPath(); ctx.arc(OX, OY, SC, 0, Math.PI*2);
ctx.strokeStyle = '#30363d'; ctx.lineWidth = 1; ctx.setLineDash([3,3]); ctx.stroke(); ctx.setLineDash([]);
// w の表示
var wp = toS(wr, wi);
ctx.beginPath(); ctx.moveTo(OX, OY); ctx.lineTo(wp[0], wp[1]);
ctx.strokeStyle = '#ffa657'; ctx.lineWidth = 2; ctx.stroke();
ctx.beginPath(); ctx.arc(wp[0], wp[1], 5, 0, Math.PI*2);
ctx.fillStyle = '#ffa657'; ctx.fill();
ctx.fillStyle = '#ffa657'; ctx.font = 'bold 12px sans-serif';
ctx.fillText('w', wp[0]+8, wp[1]-8);
// 偏角の弧
ctx.beginPath(); ctx.arc(OX, OY, 22, -phi, 0, phi < 0);
ctx.strokeStyle = '#ffa65780'; ctx.lineWidth = 2; ctx.stroke();
// 元の図形(青)
ctx.beginPath();
// 中心を (-2, -1) に配置
var offR = -2, offI = -1;
var start = toS(shape[0][0]+offR, shape[0][1]+offI);
ctx.moveTo(start[0], start[1]);
for (var i=1; i<shape.length; i++) {
var sp = toS(shape[i][0]+offR, shape[i][1]+offI);
ctx.lineTo(sp[0], sp[1]);
}
ctx.closePath();
ctx.strokeStyle = '#58a6ff'; ctx.lineWidth = 2; ctx.stroke();
ctx.fillStyle = '#58a6ff20'; ctx.fill();
// 変換後の図形(緑)
ctx.beginPath();
var tp = mulC(shape[0][0]+offR, shape[0][1]+offI, wr, wi);
var ts = toS(tp[0], tp[1]);
ctx.moveTo(ts[0], ts[1]);
for (var j=1; j<shape.length; j++) {
var qr = shape[j][0]+offR, qi = shape[j][1]+offI;
var tq = mulC(qr, qi, wr, wi);
var tqp = toS(tq[0], tq[1]);
ctx.lineTo(tqp[0], tqp[1]);
}
ctx.closePath();
ctx.strokeStyle = '#56d364'; ctx.lineWidth = 2.5; ctx.stroke();
ctx.fillStyle = '#56d36420'; ctx.fill();
// 対応点の接続(いくつかの頂点)
for (var k=0; k<shape.length; k+=3) {
var or_ = shape[k][0]+offR, oi_ = shape[k][1]+offI;
var osp = toS(or_, oi_);
var tr_ = mulC(or_, oi_, wr, wi);
var trp = toS(tr_[0], tr_[1]);
ctx.beginPath(); ctx.moveTo(osp[0],osp[1]); ctx.lineTo(trp[0],trp[1]);
ctx.strokeStyle = '#8b949e40'; ctx.lineWidth = 1; ctx.setLineDash([3,2]); ctx.stroke(); ctx.setLineDash([]);
}
// 凡例
ctx.fillStyle = '#58a6ff'; ctx.font = 'bold 12px sans-serif';
ctx.fillText('元の図形 z', OX - 4*SC, OY + 3.5*SC < H ? OY + 3.5*SC : H - 20);
ctx.fillStyle = '#56d364';
ctx.fillText('変換後 w·z', OX + 1*SC, OY - 3.5*SC > 0 ? OY - 3.5*SC : 20);
// 情報パネル
ctx.fillStyle = '#0d1117e0';
ctx.fillRect(8, 8, 270, 110);
ctx.strokeStyle = '#30363d'; ctx.lineWidth = 1;
ctx.strokeRect(8, 8, 270, 110);
ctx.font = '13px monospace';
ctx.fillStyle = '#ffa657';
ctx.fillText('w = ' + wr.toFixed(2) + (wi>=0?' + ':' - ') + Math.abs(wi).toFixed(2) + 'i', 16, 28);
ctx.fillStyle = '#e6edf3';
ctx.fillText('|w| = ' + scale.toFixed(2) + ' (スケール)', 16, 48);
ctx.fillText('arg(w) = ' + (phi*180/Math.PI).toFixed(1) + '° (回転角)', 16, 68);
ctx.fillStyle = '#56d364';
ctx.fillText('乗算 w·z = 回転 + 拡大', 16, 88);
ctx.fillStyle = '#8b949e';
ctx.fillText('左右=回転、上下=スケール', 16, 106);
requestAnimationFrame(loop);
}
loop();
一次変換としての複素数
「移動して・回して・大きさを変える」——これらを同時に行う変換を 1 つの式で表せます。
複素数を使った一次変換 ( は複素数定数)は次の合成です:
- : 倍に拡大縮小 + 回転——「 を掛ける」
- : だけ平行移動——「 を足す」
例: 回転+ 平行移動
- : 回転——「 を掛けると 90° 回る」
- : 平行移動——「点 に対応する複素数を足す」
原点以外を中心とした回転
「公園の木を中心に、周りをぐるっと回る」——原点以外を中心にした回転も複素数で表せます。
点 を中心に角 回転する変換:
ステップ:
- だけ平行移動()して原点を中心に——「 を原点に持ってくる」
- を掛けて回転——「原点中心の回転」
- だけ逆平行移動して戻す——「元の位置に戻す」
メビウス変換(発展)
この変換は「円や直線を円や直線に写す」という美しい性質を持ちます(円と直線を統一的に「一般化された円」と見なす)——「直線は半径無限大の円」と考えると、両者を同一視できます。
高校範囲を超えますが、フラクタルや双曲幾何学の基盤です。
複素数変換の応用例
正三角形の頂点を生成
「等間隔に 3 等分した位置に点を打つ」—— ずつ回転を繰り返すだけです:
頂点 を ずつ回転:
3 点は単位円上に等間隔に並びます——「正三角形の頂点は単位円を 3 等分する点」です。
余弦定理の複素数版
三角形の頂点を とするとき:
これは と同じ内容です——「ベクトルの内積と複素数の実部が対応している」ことが分かります。
まとめ
- を掛ける = 倍拡大縮小 + 回転——「乗算一発で回転と拡大縮小が実現」
- は拡大・回転・平行移動の合成——「3 つの変換をまとめた強力な公式」
- 原点以外を中心とした回転:——「ずらして・回して・戻す」
- 複素数の乗算は、ベクトルの「回転行列」と本質的に同じ操作——「複素数の掛け算は行列の回転変換と同値」
次回は複素数平面の締めくくりとして、「1 の n 乗根」と図形の関係を学びます。