複素数
数学では複素数 z を \(x + iy\) と表記します。x を実部、y を虚部、i を虚数単位といいます。虚数単位は 2 乗すると -1 になる数です。複素数 \(z = x + iy\) の虚部の符号を反転した数 \(x - iy\) を「複素共役」といいます。複素数を極形式 \(z = |z|(\cos \theta + i \sin \theta)\) で表した場合、\(|z|\) を絶対値、\(\theta\) を偏角といいます。絶対値 \(|z|\) の定義は \(\sqrt{x^2 + y^2}\) です。
絶対値を求める場合、定義をそのままプログラムすると二乗の計算でオーバーフローすることがあります。参考文献 1 によると、次のように場合分けすることで、\(x^2\) や \(y^2\) で生じ得る上位桁あふれを回避することができるそうです。
\(
\sqrt{x^2 + y^2} =
\begin{cases}
|x| \sqrt{1 + \left(\dfrac{y}{x}\right)^2} \quad & \mathrm{if} \ |x| \geqq |y| \\
|y| \sqrt{1 + \left(\dfrac{x}{y}\right)^2} \quad & \mathrm{otherwise}
\end{cases}
\)
●四則演算
複素数の四則演算は次のようになります。
\(
\begin{array}{l}
(a + bi) + (c + di) = (a + c) + (b + d)i \\
(a + bi) - (c + di) = (a - c) + (b - d)i \\
(a + bi) \times (c + di) = (ac - bd) + (bc + ad)i \\
(a + bi) \div (c + di) = \dfrac{ac + bd + (bc - ad)i}{c^2 + d^2}
\end{array}
\)
除算の場合、絶対値の計算と同様にオーバーフローの対策が必要になります。
Python での実行例を示します。Python は複素数 \(z = x + iy\) を x + yj と表記します。実部 x を省略すると x は 0.0 になります。虚部 y を省略することはできません。1 + j はエラーになるので、1 + 1j と書いてください。
>>> a = 1 + 2j
>>> a
(1+2j)
>>> b = 3 + 4j
>>> b
(3+4j)
>>> a + b
(4+6j)
>>> a - b
(-2-2j)
>>> a * b
(-5+10j)
>>> a / b
(0.44+0.08j)
●指数関数と対数関数
複素数を引数にとる指数関数は「オイラーの公式 (Euler's formula)」から導くことができます。
\(
\begin{array}{l}
e^{i\theta} = \cos \theta + i \sin \theta \quad (Euler's formula) \\
\begin{eqnarray}
e^{x+iy} &=& e^x e^{iy} \\
&=& e^x (\cos y + i \sin y)
\end{eqnarray}
\end{array}
\)
複素数の対数関数は複素数 z を絶対値 \(|z|\) と偏角 \(\theta\) を使って導くことができます。
\(
\begin{array}{l}
x + iy = |z| e^{i\theta} \\
\begin{eqnarray}
\log_e (x + iy) &=& log_e |z| e^{i\theta} \\
&=& log_e |z| + log_e e^{i\theta} \\
&=& log_e |z| + i\theta, \quad (-\pi \leq \theta \leq \pi)
\end{eqnarray}
\end{array}
\)
複素数 x, y のべき乗 \(x^y\) は次式で求めることができます。
\(x^y = e^{y\log x}\)
関数 \(\log z \ (z = x + iy)\) は負の実軸 (\(-\infty \lt x \lt 0\)) において、\(x + 0.0i\) と \(x - 0.0i\) では値が異なります。Python での実行例を示します。Python のモジュール cmath をインポートしてください。
>>> cmath.log(complex(-1.0, 0.0))
3.141592653589793j
>>> cmath.log(complex(-1.0, -0.0))
-3.141592653589793j
>>> cmath.log(complex(-2.0, 0.0))
(0.6931471805599453+3.141592653589793j)
>>> cmath.log(complex(-2.0, -0.0))
(0.6931471805599453-3.141592653589793j)
>>> cmath.log(complex(-1e300, 0.0))
(690.7755278982137+3.141592653589793j)
>>> cmath.log(complex(-1e300, -0.0))
(690.7755278982137-3.141592653589793j)
このように、関数 \(\log z\) は負の実軸上で 2 つの値を持ちます。数学では値を一つ返す関数を一価関数、複数の値を返す関数を多価関数といいます。ここで、定義域を制限することで多価関数を一価関数にみなすことを考えます。関数 \(\log z\) の場合、負の実軸を定義域から取り除けば、\(\log z\) を一価関数とみなすことができるわけです。
参考 URL 2 によると、この取り除いた領域を branch cut と呼ぶそうです。プログラミングでは branch cut を定義域から取り除くのではなく、その領域では不連続な関数とするそうです。Python のモジュール cmath のドキュメントには、\(\log\) は「分枝切断を一つもち、0 から負の実数軸に沿って \(-\infty\) へと延びており」と記述されています。Python のマニュアルに合わせて、本稿でも branch cut を「分枝切断」と記述することにします。
プログラミング言語の場合、0.0 と -0.0 を区別する処理系であれば、Python のように 2 つの値を区別することができます。0.0 と -0.0 を区別しない処理系では、偏角 \(\theta\) の範囲を \(-\pi \lt \theta \leq \pi\) に制限することで、\(\log z\) の返り値を (\(-\pi\) を取り除いて) 一つにすることができます。
●三角関数
複素数の三角関数の定義は、オイラーの公式から導かれる式の \(\theta\) を複素数 \(z\) に変えたものになります。
\(\sin -\theta = -\sin \theta, \ \cos -\theta = \cos \theta \) より
\(
\begin{eqnarray}
e^{i(-\theta)} &=& \cos -\theta + i \sin -\theta \\
&=& \cos \theta - i \sin \theta
\end{eqnarray}
\)
\(
\begin{array}{l}
e^{i\theta} + e^{-i\theta} = 2 \cos \theta \\
\cos \theta = \dfrac{e^{i\theta} + e^{-i\theta}}{2} \\
e^{i\theta} - e^{-i\theta} = 2i \sin \theta \\
\sin \theta = \dfrac{e^{i\theta} - e^{-i\theta}}{2i}
\end{array}
\)
\(\theta\) を複素数 z に置き換えた式が三角関数の定義になる
\(
\begin{eqnarray}
\sin z = \dfrac{e^{iz} - e^{-iz}}{2i} \\
\cos z = \dfrac{e^{iz} + e^{-iz}}{2}
\end{eqnarray}
\)
\(\sin z, \cos z\) に純虚数 \(ix\) を与えると双曲線関数 (\(\sinh x, \cosh x\)) になります。
双曲線関数の定義
\(\begin{eqnarray}
\sinh x = \dfrac{e^x - e^{-x}}{2} \\
\cosh x = \dfrac{e^x + e^{-x}}{2}
\end{eqnarray}\)
\(\begin{eqnarray}
\sin ix &=& \dfrac{e^{iix} - e^{-iix}}{2i} \\
&=& \dfrac{e^{-x} - e^x}{2i} \times \dfrac{-i}{-i} \\
&=& i \dfrac{e^x - e^{-x}}{2} \\
&=& i \sinh x \\
\cos ix &=& \dfrac{e^{iix} + e^{-iix}}{2} \\
&=& \dfrac{e^{-x} + e^x}{2} \\
&=& \cosh x
\end{eqnarray}\)
これに三角関数の加法定理 [*1] を使うと次の式が導かれます。
\(\begin{eqnarray}
\sin (x + iy) &=& \sin x \cos iy + \cos x \sin iy \\
&=& \sin x \cosh y + i \cos x \sinh y \\
\cos (x + iy) &=& \cos x \cos iy - \sin x \sin iy \\
&=& \cos x \cosh y - i \sin x \sinh y \\
\tan (x + iy) &=& \dfrac{\sin 2x + \sin 2iy}{cos 2x + cos 2iy} \\
&=& \dfrac{\sin 2x + i \sinh 2y}{\cos 2x + \cosh 2y}
\end{eqnarray}\)
-- note --------
[*1] 三角関数の公式は引数が複素数でも成り立ちます。ただし、\(|\sin x| \leq 1, |\cos x| \leq 1\) という関係式は、x が実数だと成立しますが複素数では成立しません。
●双曲線関数
複素数の双曲線関数の定義は、実数の定義で引数 x を複素数 \(z\) に変えたものになります。
双曲線関数の定義 (\(z\) は複素数)
\(\begin{eqnarray}
\sinh z = \dfrac{e^{z} - e^{-z}}{2} \\
\cosh z = \dfrac{e^{z} + e^{-z}}{2}
\end{eqnarray}\)
\(\sinh z, \cosh z\) に純虚数 \(ix\) を与えると三角関数 (\(\sin x, \cos x)\) になります。
\(\begin{eqnarray}
\sinh ix &=& \dfrac{e^{ix} - e^{-ix}}{2} \\
&=& \dfrac{e^{ix} - e^{-ix}}{2} \times \dfrac{i}{i} \\
&=& i \dfrac{e^{ix} - e^{-ix}}{2i} \\
&=& i \sin x \\
\cosh ix &=& \dfrac{e^{ix} + e^{ix}}{2} \\
&=& \cos x
\end{eqnarray}\)
これに双曲線関数の加法定理を使うと、次の式が導かれます。
双曲線関数の加法定理
\(\begin{eqnarray}
\sinh(x + y) &=& \sinh x \cosh y + \cosh x \sinh y \\
\cosh(x + y) &=& \cosh x \cosh y + \sinh x \sinh y \\
\tanh(x + y) &=& \dfrac{\sinh(x + y)}{\cosh(x + y)} \\
&=& \dfrac{\sinh 2x + \sinh 2y}{\cosh 2x + \cosh 2y}
\end{eqnarray}\)
\(\begin{eqnarray}
\sinh(x + iy) &=& \sinh x \cos y + i \cosh x \sin y \\
\cosh(x + iy) &=& \cosh x \cos y + i \sinh x \sin y \\
\tanh(x + iy) &=& \dfrac{\sinh(x + iy)}{\cosh(x + iy)} \\
&=& \dfrac{\sinh 2x + i \sin 2y}{\cosh 2x + \cos 2y}
\end{eqnarray}\)
●平方根
複素数 z の平方根は次の式で求めることができます。
\(z = x + iy, \ |z| = \sqrt{x^2 + y^2}, \ \theta = \arg z \ (-\pi \leqq \theta \leqq \pi)\) とすると
\(
\sqrt{x + iy} = \begin{cases}
\sqrt{|z| e^{i\theta}} = \sqrt{|z|} e^{i\theta/2} & (1) \\
\sqrt{|z| e^{i\theta + 2\pi}} = \sqrt{|z|} e^{i\theta/2 + \pi} & (2)
\end{cases}
\)
式 (1) を平方根の主値といいます。角度は \(2\pi\) を足すと同じ角度になるので、式 (2) がもう一つの解になります。三角関数の半角の公式を使うと、式 (1) から次の式が導かれます。
三角関数の半角の公式
\(\begin{eqnarray}
\sin^2{\left(\frac{\theta}{2}\right)} = \dfrac{1 - \cos \theta}{2} \\
\cos^2{\left(\frac{\theta}{2}\right)} = \dfrac{1 + \cos \theta}{2}
\end{eqnarray}\)
\(y \geqq 0\) の場合
\(\begin{eqnarray}
\sqrt{|z|} e^{i\theta/2} &=& \sqrt{|z|} \left(\cos{\frac{\theta}{2}} + i \sin{\frac{\theta}{2}}\right) \\
&=& \sqrt{|z|} \left(\sqrt{\frac{1 + \cos \theta}{2}}) + i \sqrt{\frac{1 - \cos \theta}{2}}\right) \\
&=& \dfrac{\sqrt{|z| + |z|\cos \theta}}{2} + i \sqrt{\frac{|z| - |z| \cos \theta}{2}} \\
&=& \sqrt{\frac{|z| + x}{2}} + i \sqrt{\frac{|z| - x}{2}}, \quad (|z|\cos \theta = x)
\end{eqnarray}\)
\(y \lt 0\) の場合、虚部の符号が \(-\) になる
\(
\sqrt{|z|} e^{i\theta/2} = \sqrt{\dfrac{|z| + x}{2}} - i \sqrt{\dfrac{|z| - x}{2}}
\)
\(\sqrt x\) は \(\log x\) と同じ分枝切断を持っています。x を負の整数とすると sqrt(x) の解は \(i \sqrt x\) になりますが、もうひとつ \(-i \sqrt x\) という解があります。Python での実行例を示します。
>>> cmath.sqrt(complex(-1, 0.0))
1j
>>> cmath.sqrt(complex(-1, -0.0))
-1j
>>> cmath.sqrt(complex(-2, 0.0))
1.4142135623730951j
>>> cmath.sqrt(complex(-2, -0.0))
-1.4142135623730951j
>>> cmath.sqrt(complex(-1e300, 0.0))
1e+150j
>>> cmath.sqrt(complex(-1e300, -0.0))
-1e+150j
●逆三角関数 (複素数)
複素数の逆三角関数の定義は、複素数の三角関数の定義から導くことができます。\(\arcsin z\) の定義は次のようになります。
\(z, w\) は複素数とする
\(\begin{array}{l}
\arcsin z = w \\
z = \sin w = \dfrac{e^{iw} - e^{-iw}}{2i} \\
z \times 2ie^{iw} = \dfrac{e^{iw} - e^{-iw}}{2i} \times 2ie^{iw} \\
2iz(e^{iw}) = (e^{iw})^2 - 1 \\
(e^{iw})^2 - 2iz(e^{iw}) - 1 = 0
\end{array}\)
\(e^{iw}\) の二次方程式と考えて解くと
\(e^{iw} = iz \pm \sqrt{1 - z^2}\)
両辺の対数をとって \(-i\) を掛け算し、平方根の主値 \(+\) を選ぶ
\(w = \arcsin z = -i \log{\left(iz + \sqrt{1 - z^2}\right)} \)
\(\arccos z, \arctan z\) は定義だけを示します。
\(\begin{array}{l}
\arccos z = \dfrac{\pi}{2} - \arcsin z \\
\arctan z = i \dfrac{\log{\left(1 - iz\right)} - \log{\left(1 + iz\right)}}{2}
\end{array}\)
\(\arcsin z, \arccos z, \arctan z\) は次に示す分枝切断を持っています。
- \(\arcsin z\) は実軸上の \(-\infty \lt -1\) と \(1 \lt \infty\)
- \(\arccos z\) は \(\arcsin z\) と同じ
- \(\arctan z\) は虚軸上の \(-\infty \lt -1\) と \(1 \lt \infty\)
Python での実行例は拙作のページ お気楽 Python3 超入門: 複素数 をお読みくださいませ。
●逆双曲線関数 (実数)
双曲線関数の逆関数を「逆双曲線関数 (inverse hyperbolic function)」といいます。ここでは逆双曲線関数を \(\sinh^{-1} x, \cosh^{-1} x, \tanh^{-1} x \) で表すことにします。双曲線関数と逆双曲線関数の定義域と値域を示します。
\(\begin{array}{lcc}
y = \sinh x & -\infty \lt x \lt \infty & -\infty \lt y \lt \infty \\
y = \cosh x & -\infty \lt x \lt \infty & 1 \leqq y \lt \infty \\
y = \tanh x & -\infty \lt x \lt \infty & -1 \lt y \lt 1 \\
y = \sinh^{-1} x & -\infty \lt x \lt \infty & -\infty \lt y \lt \infty \\
y = \cosh^{-1} x & 1 \leqq x \lt \infty & 0 \leqq y \lt \infty \\
y = \tanh^{-1} x & -1 \lt x \lt 1 & -\infty \lt y \lt \infty
\end{array}\)
x と y は実数です。\(x = \cosh y\) の逆関数 \(y = \cosh^{-1} x\) を満たす y の値は 2 つありますが、ここでは \(y \geqq 0\) を主値として選ぶことにします。
逆双曲線関数の定義は双曲線関数の定義から導くことができます。
\(\begin{array}{l}
\sinh^{-1} x = y \\
y = \sinh x = \dfrac{e^{x} - e^{-x}}{2} \\
y \times 2e^{x} = \dfrac{e^{x} - e^{-x}}{2} \times 2e^{x} \\
2ye^{x} = e^{2x} - 1 \\
e^{2x} - 2ye^{x} - 1 = 0
\end{array}\)
\(e^{x}\) の 2 次方程式として解く
\(e^{x} = \dfrac{2y \pm \sqrt{4y^2 + 4}}{2} = y \pm \sqrt{y^2 + 1} \)
\(e^{x} \gt 0\) だから平方根の符号に \(+\) を選んで対数をとる
\(x = \log \left(y + \sqrt{y^2 + 1}\right)\)
\(\begin{array}{l}
\cosh^{-1} x = y \\
y = \cosh x = \dfrac{e^{x} + e^{-x}}{2} \\
y \times 2e^{x} = \dfrac{e^{x} + e^{-x}}{2} \times 2e^{x} \\
2ye^{x} = e^{2x} + 1 \\
e^{2x} - 2ye^{x} + 1 = 0
\end{array}\)
\(e^{x}\) の 2 次方程式として解く
\(e^{x} = \dfrac{2y \pm \sqrt{\left(4y^2 - 4\right)}}{2} = y \pm \sqrt{y^2 - 1} \)
\(e^{x} \gt 0\) だから平方根の符号に \(+\) を選んで対数をとる
\(x = \log \left(y + \sqrt{y^2 - 1}\right), \quad (y \geqq 1) \)
\(\begin{array}{l}
\tanh^{-1} x = y \\
\begin{eqnarray}
y &=& \tanh x \\
&=& \dfrac{\sinh x}{\cosh x} \\
&=& \dfrac{e^{x} - e^{-x}}{e^{x} + e^{-x}} \\
&=& \dfrac{e^{2x} - 1}{e^{2x} + 1}
\end{eqnarray} \\
y(e^{2x} + 1) = (e^{2x} - 1) \\
(1 - y)e^{2x} = 1 + y \\
e^{2x} = \dfrac{1 + y}{1 - y} \\
x = \dfrac{1}{2} \log{\dfrac{1 + y}{1 - y}}
\end{array}\)
関数 \(\tanh^{-1} x\) を使うと、次の関係式から \(\sinh^{-1} x, \ \cosh^{-1} x\) を求めることができます。
\(\sinh^{-1} x = \tanh^{-1}{\dfrac{x}{\sqrt{x^2 + 1}}} \)
\(\cosh^{-1} x = \tanh^{-1}{\dfrac{\sqrt{1 - x^2}}{x}} \)
●逆双曲線関数 (複素数)
複素数の逆双曲線関数の定義は、実数の定義で引数 x を複素数 z に変えたものになります。
\(\begin{array}{l}
\sinh^{-1} z = \log \left(z + \sqrt{z^2 + 1}\right) \\
\begin{eqnarray}
\cosh^{-1} z &=& \log \left(z + \sqrt{z^2 - 1}\right) \quad &(1)& \\
&=& \log \left(z + \sqrt{z + 1} \sqrt{z - 1}\right) \quad &(2)&
\end{eqnarray} \\
\tanh^{-1} z = \dfrac{1}{2} \log\left(\dfrac{1 + z}{1 - z}\right) = \dfrac{1}{2} \left( \log {\left( 1 + z \right)} - \log {\left(1 - z\right)} \right)
\end{array}\)
参考文献, URL 2 によると、\(\cosh^{-1} z\) を式 (1) でプログラムすると「分枝切断線」が複雑になるため、他の式 (たとえば (2) など) でプログラムする処理系が多いようです。ちなみに、ANSI Common Lisp では \(\cosh^{-1} z\) を次の式で定義しています。
\(
\cosh^{-1} z = 2 \log \left( \sqrt{\dfrac{z + 1}{2}} + \sqrt{\dfrac{z - 1}{2}} \right)
\)
\(\sinh^{-1} z, \cosh^{-1} z, \tanh^{-1} z\) は次に示す分枝切断を持っています。
- \(\sinh^{-1} z\) は虚軸上の \(-\infty \lt -1\) と \(1 \lt \infty\)
- \(\cosh^{-1} z\) は実軸上の \(-\infty \lt 1\), (式 2)
- \(\tanh^{-1} z\) は実軸上の \(-\infty \lt -1\) と \(1 \lt \infty\)
Python での実行例は拙作のページ お気楽 Python3 超入門: 複素数 をお読みくださいませ。
●参考文献, URL
- 奥村晴彦,『C言語による最新アルゴリズム事典』, 技術評論社, 1991
- 逆双曲線関数と逆三角関数の branch cut | 雑記帳