Loading...
fpsのニュートン法高速化(簡易版)
概要
サイズ
n
n
n
のFFTを行うときの計算量をF(n)と表します。
唐突ですが、
f
f
f
のinvを計算するニュートン法は次のようなものでした。
g
2
n
=
g
n
−
ϵ
n
g
n
g_{2n}=g_n-\epsilon_ng_n
g
2
n
=
g
n
−
ϵ
n
g
n
ここで、
ϵ
n
=
f
n
g
n
−
1
\epsilon _n =f_ng_n-1
ϵ
n
=
f
n
g
n
−
1
上記の式をナイーブに計算すると、
ϵ
n
\epsilon_n
ϵ
n
の計算で
3
F
(
4
n
)
3F(4n)
3
F
(
4
n
)
、
g
2
n
g_{2n}
g
2
n
の計算で
3
F
(
4
n
)
3F(4n)
3
F
(
4
n
)
かかるので、トータル
6
F
(
4
n
)
6F(4n)
6
F
(
4
n
)
回の計算が行われます。
寄り道
ところで、演算の順序を工夫すると、かなり速くなります(noshiさんが教えてくれた):
g
2
n
=
2
g
n
−
(
g
n
)
2
f
n
g_{2n}=2g_n-(g_n)^2f_n
g
2
n
=
2
g
n
−
(
g
n
)
2
f
n
(
g
n
)
2
(g_n)^2
(
g
n
)
2
の計算を長さ4nのDFTでやることにすると、
F
(
4
n
)
F(4n)
F
(
4
n
)
で
(
g
n
)
2
(g_n)^2
(
g
n
)
2
のDFTが手に入って、
d
e
g
(
g
n
)
2
<
2
n
deg (g_n)^2 < 2n
d
e
g
(
g
n
)
2
<
2
n
であることから、そのまま
(
g
n
)
2
f
n
(g_n)^2 f_n
(
g
n
)
2
f
n
の計算に使えます。
f
n
f_n
f
n
のDFTと、最後のIDFTで
2
F
(
4
n
)
2F(4n)
2
F
(
4
n
)
使うので、トータルで
3
F
(
4
n
)
3F(4n)
3
F
(
4
n
)
となります。
これ実装楽だしかなり速いので、とりあえずこの実装を採用するとコスパよい
本題
g
n
g_n
g
n
から
g
2
n
g_{2n}
g
2
n
を
5
F
(
2
n
)
5F(2n)
5
F
(
2
n
)
で得る方法を紹介します。(先ほどの方法と比べると、こちらのほうがサイズ
2
n
2n
2
n
のFFT 1回分くらいお得です。また、ここで紹介する手法を転用すると、他の演算(quotient,sqrt,log,exp)が2倍くらい速くなったりします。
まずは
ϵ
n
=
f
n
g
n
−
1
m
o
d
x
2
n
\epsilon_n=f_ng_n-1 \ \ \ mod \ \ \ x^{2n}
ϵ
n
=
f
n
g
n
−
1
m
o
d
x
2
n
を計算します:
G
n
G_n
G
n
、
F
n
F_n
F
n
を、それぞれ
g
n
g_n
g
n
、
f
n
f_n
f
n
のサイズ
2
n
2n
2
n
のDFTとします。これらは、
2
F
(
2
n
)
2F(2n)
2
F
(
2
n
)
回のFFTで計算できます。
次に、
G
n
G_n
G
n
と
F
n
F_n
F
n
の要素ごとの積をとります。このとき、
d
e
g
(
f
n
g
n
)
≥
2
n
deg (f_n g_n) \geq 2n
d
e
g
(
f
n
g
n
)
≥
2
n
であることから、循環が発生します。演算結果をIDFTします。(得られた多項式を
h
n
h_n
h
n
とおきます(
d
e
g
h
n
<
2
n
deg h_n <2n
d
e
g
h
n
<
2
n
))
h
n
h_n
h
n
の
[
0
,
n
)
[0,n)
[
0
,
n
)
次の係数は、実際には
f
n
g
n
f_ng_n
f
n
g
n
の
[
0
,
n
)
[0,n)
[
0
,
n
)
次の係数と
[
2
n
,
3
n
)
[2n,3n)
[
2
n
,
3
n
)
次の係数の重ね合わせとなっています(循環畳み込みなので!)
同様に、
h
n
h_n
h
n
の
[
n
,
2
n
)
[n,2n)
[
n
,
2
n
)
次の係数は、
f
n
g
n
f_ng_n
f
n
g
n
の
[
n
,
2
n
)
[n,2n)
[
n
,
2
n
)
次の係数と
[
3
n
,
4
n
)
[3n,4n)
[
3
n
,
4
n
)
次の係数の重ね合わせになっています。
今、
f
n
g
n
f_ng_n
f
n
g
n
の
[
0
,
2
n
)
[0,2n)
[
0
,
2
n
)
次の係数だけが欲しいので、困ってしまいます。
ところが、
f
n
g
n
≡
1
m
o
d
x
n
f_ng_n \equiv 1 \ mod \ x^n
f
n
g
n
≡
1
m
o
d
x
n
なので、
[
0
,
n
)
[0,n)
[
0
,
n
)
の係数は
1
,
0
,
0
,
.
.
.
1,0,0,...
1
,
0
,
0
,
.
.
.
です。
また、
d
e
g
g
n
<
n
deg \ g_n < n
d
e
g
g
n
<
n
より
d
e
g
f
n
g
n
<
3
n
deg \ f_ng_n < 3n
d
e
g
f
n
g
n
<
3
n
なので、
h
n
h_n
h
n
の
[
n
,
2
n
)
[n,2n)
[
n
,
2
n
)
次の係数(
f
n
g
n
f_ng_n
f
n
g
n
の
[
n
,
2
n
)
[n,2n)
[
n
,
2
n
)
次の係数と
[
3
n
,
4
n
)
[3n,4n)
[
3
n
,
4
n
)
次の係数の重ね合わせ)は、実際には
f
n
g
n
f_ng_n
f
n
g
n
の
[
n
,
2
n
)
[n,2n)
[
n
,
2
n
)
次の係数と一致します。
上記の計算量は
3
F
(
2
n
)
3F(2n)
3
F
(
2
n
)
です。
→解決
上記の手法の本質は、
f
n
g
n
f_ng_n
f
n
g
n
の
[
0
,
n
)
[0,n)
[
0
,
n
)
次と
[
3
n
,
4
n
)
[3n,4n)
[
3
n
,
4
n
)
次の係数が分かっているおかげで、(サイズを2倍せずに)普通に循環畳み込みをやっても、各係数を復元できることです。
次に、
g
2
n
=
g
n
−
ϵ
n
g
n
g_{2n}=g_n-\epsilon_n g_n
g
2
n
=
g
n
−
ϵ
n
g
n
の計算を考えます。先ほどと同様に
d
e
g
g
n
<
n
deg \ g_n < n
d
e
g
g
n
<
n
なので、
ϵ
n
g
n
\epsilon _n g_n
ϵ
n
g
n
の
[
3
n
,
4
n
)
[3n,4n)
[
3
n
,
4
n
)
次の係数は0です。また、
ϵ
n
\epsilon_n
ϵ
n
の
[
0
,
n
)
[0,n)
[
0
,
n
)
次の係数は0(これは、すぐにわかります)なので、
ϵ
n
g
n
\epsilon_ng_n
ϵ
n
g
n
の
[
0
,
n
)
[0,n)
[
0
,
n
)
次の係数は0です。
従って先ほどと同様に循環畳み込みを用いることができて、
3
F
(
2
n
)
3F(2n)
3
F
(
2
n
)
回の計算で出来ます。
ところで、
g
n
g_n
g
n
のサイズ
2
n
2n
2
n
のDFTは使いまわせるので、
F
(
2
n
)
F(2n)
F
(
2
n
)
回の計算を削減することができて、全体で
5
F
(
2
n
)
5F(2n)
5
F
(
2
n
)
回でできます。
Please turn on JavaScript to use Paper in all of its awesomeness. ^_^
概要
寄り道
本題