zzの逆関数(5)

一般の c に対して、

 z^z = c

を解く。

 z\log{z} = \log{c}

ここで、

 u = \log{z}
 a = \log{c}

とおく。
ただし、aは虚部が実部の絶対値より大きく、
aの絶対値が1より大きくなるように虚部を調整しておく。
そうすると、

 u \equiv e^{v+iw}
 v + e^v\cos{w} = \mbox{Re}a
 w + e^v\sin{w} = \mbox{Im}a


以前と同じようなグラフが描けて、同じように解ける。
以下、ソース。
ただし、あまり検証していない。



import std.cstream;
import std.math;

void main() {
cdouble z = rev_zz(-2-1i);
dout.writefln("%f", z);
dout.writefln(pow(z, z));
}

cdouble rev_zz(cdouble c) {
cdouble a = log(c);
if(abs(a.re) >= a.im) {
int n = cast(int)( (abs(a.re) - a.im)
/ 2 / std.math.PI);
a += n * 2i * std.math.PI;
}
if(a.im <= 1)
a += 2i * std.math.PI;

cdouble b = log(a);
double w = b.im / (1 + b.re);
double v = std.math.log( (b.im - w) / sin(w));
cdouble u = exp(v + 1i * w);

cdouble du;
do {
du = u * exp(u) - a;
u -= du / (u + 1) / exp(u);
} while(abs(du) > 1e-10);

return exp(u);
}

cdouble exp(cdouble c) {
double im = c.im;
return std.math.exp(c.re) * (cos(im) + 1i * sin(im));
}

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 pow(cdouble z, cdouble a) {
if(z == 0 + 0i) {
if(a == 0 + 0i)
return 1 + 0i;
else
return 0 + 0i;
}
else {
return exp(a * log(z));
}
}