複素数(6)

acos

 \cos{Z} = \frac{e^{iZ} + e^{-iZ}}{2}

をzとおくと、eiZ2次方程式となり、
これを解くと、

 e^{iZ} = z \pm\sqrt{z^2 - 1}
 Z = \mp{i}\log{(z + sqrt{z^2 - 1}})

より、

 \mbox{acos}{z} = \mp{i}\log{(z + sqrt{z^2 - 1})}

ただし、logが2π周期で、頭に±がついている。


主値は、C++では定義されていない?
C99ではあるらしい。

http://docs.hp.com/ja/B2355-60104-06/cacos.3M.html

値域は、実部が[0, π]だということである。
logは虚部が[-π, π]だから、適当に符号を選べばよい。


import std.cstream;
import std.math;

void main(char[][] args) {
dout.writefln(acos(1+1i)); // 0.904557+-1.06128i
dout.writefln(acos(1-1i)); // 0.904557+1.06128i
}

cdouble acos(cdouble z) {
cdouble c = 1i * log(z + sqrt(z * z - 1));
if(c.re >= 0)
return c;
else
return -c;
}

cdouble log(cdouble z) {
double x = z.re;
double y = z.im;
return std.math.log(x * x + y * y) / 2 + 1i * atan2(y, x);
}

cdouble sqrt(cdouble z) {
double x = z.re;
double y = z.im;
double theta = atan2(y, x) / 2;
return std.math.sqrt(abs(z)) *
(std.math.cos(theta) + 1i * std.math.sin(theta));
}


asinは、値域が[-π/2, π/2]で、

http://docs.hp.com/ja/B2355-60104-06/casin.3M.html

 \mbox{asin}{z} = -i\log{(iz \pm\sqrt{1 - z^2})}

logの中の両方の積が-1であることから、
どちらかの実部が0以上となる。
そちらのlogを取ると、虚部の絶対値がπ/2以下になる。
(ややあいまいな部分があるが、ここでは気にしないことにする)


import std.cstream;
import std.math;

void main(char[][] args) {
dout.writefln(asin(1+1i));
dout.writefln(asin(1-1i));
}

cdouble asin(cdouble z) {
cdouble c = sqrt(1 - z * z);
cdouble s1 = 1i * z + c;
if(s1.re >= 0)
return -1i * log(s1);
else
return -1i * log(1i * z - c);
}

// 以下のlogとsqrtの定義は略