【数学】ゲーム開発で覚えておくべき複素数の性質

ゲーム開発に必要な複素数の知識をまとめてみました。
あくまでゲーム開発に必要な部分のみ。深入りはしません。

虚数単位と複素数

まず虚数単位とは「二乗したら-1となる数」で、 {i}と表記されます。

 { \displaystyle
i \times i = -1
}

ある数(実数)を二乗するとき、その数が負の値でも正の値でも結果は正の値になります。
そう考えると、「二乗したら-1になる数」は実際には存在しない想像上の数(虚数)だと言えます。

そして複素数とは、実数 {a} {b}虚数単位 {i}を組み合わせて、 {a+ib}の形で表した数のことです。
 {a}を実数部、 {ib}虚数部と呼びます。

 { \displaystyle
5+2i
}複素数の一例)

複素数平面と共役複素数

複素数平面とは、横軸を実数の軸(実軸)、縦軸を虚数の軸(虚軸)とし、
複素数を二次元にプロットできるようにした平面です。

f:id:halya_11:20180722013359p:plain:w400

例えば、複素数 {3+2i}複素数平面上では次のように表されます。

f:id:halya_11:20180722013848p:plain:w400

また、複素数 {a+bi}に対して {a-bi}を共役複素数と呼びます。
これは複素数平面においては実数軸に対して反転した位置にプロットされます。

f:id:halya_11:20180722014255p:plain:w400

複素数の積の性質

ゲームにおいて複素数同士の積の性質が重要です。
複素数同士の積の結果を複素数平面にプロットすると次のような性質があることがわかります。

  1. 積の値の偏角は元の二つの偏角の和となる
  2. 積の値の長さは元の二つの長さの積となる
    偏角: 原点からプロットした点への線分が実軸の正方向となす角のこと

よくわからないと思うので具体例を見てみます。

いま、 {1+ \sqrt{3}i} {\sqrt{3}+i}の積を考えます。
複素数 {a+bi} {c+di}の積の式は次のように整理できます。

 { \displaystyle
(a+bi)(c+di)=(ac-bd)+i(ad+bc)
}

これを用いると、

 { \displaystyle
(1+ \sqrt{3}i)(\sqrt{3}+i)=4i
}

となります。
これをプロットすると次のようになります。

f:id:halya_11:20180722214634p:plain:w400

まず、積の値の偏角(90°)が元の二つの偏角(30°と60°)の和になっていること、
すなわち上記の1の性質が確認できます。

また、積の値の長さ(4)は元の二つの長さ(√4と√4)の積となっていること、
すなわち上記の2の性質が確認できます。

これで複素数の積の性質が確認できました。
1.の性質は特に重要なので、次節で実用的な使い方を見て行きます。

実用的な使い方1:複素数から偏角を求める

複素数複素数平面上で示す偏角を求めるにはMathf.Atan2()使います。
これは三角関数の性質から自明です。

using UnityEngine;

public class ComplexSample : MonoBehaviour
{
    private void Awake()
    {
        // 複素数 √3+i の偏角を求める
        var rad = Mathf.Atan2(1, Mathf.Sqrt(3));
        Debug.Log(Mathf.Rad2Deg * rad); // 30
    }
}

実用的な使い方2:ある角度から一定の角度回転した角度を求める

 {\sqrt{3}+i}(30°)を{i}(90°)回転させた角度を求めてみます。
複素数同士の積の偏角は元の二つの偏角の和となる性質を使います。

using UnityEngine;

public class ComplexSample : MonoBehaviour
{

    public class Complex
    {
        public float x;
        public float y;

        public Complex(float x, float y)
        {
            this.x = x;
            this.y = y;
        }

        public static Complex operator *(Complex a, Complex b)
        {
            return new Complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
        }
    }

    private void Awake()
    {
        var comp = new Complex(Mathf.Sqrt(3), 1);
        comp *= new Complex(0, 1);
        var rad = Mathf.Atan2(comp.y, comp.x);
        Debug.Log(Mathf.Rad2Deg * rad); // 120
    }
}

実用的な使い方3:二つの角度の差分を求める

複素数同士の積の性質を応用して、 {\sqrt{3}+i}(30°)と {i}(90°)との角度の差分を求めてみます。
差分を求めるにはまずどちらかの複素数の共役複素数を求め、それと他方の複素数の積を求めます。
その絶対値が角度の差分となります。

using UnityEngine;

public class ComplexSample : MonoBehaviour
{

    public class Complex
    {
        public float x;
        public float y;

        public Complex(float x, float y)
        {
            this.x = x;
            this.y = y;
        }

        public static Complex operator *(Complex a, Complex b)
        {
            return new Complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
        }
    }

    private void Awake()
    {
        var comp1 = new Complex(Mathf.Sqrt(3), 1);
        var comp2 = new Complex(0, 1);
        
        // 共役複素数を求める
        comp2.y *= -1;
        
        var comp = comp1 * comp2;
        var rad = Mathf.Atan2(comp.y, comp.x);
        rad = Mathf.Abs(rad);
        Debug.Log(Mathf.Rad2Deg * rad); // 60
    }
}

関連

light11.hatenadiary.com