Binary Splitting
Binary Splitting Method
簡易版
まずは広く使われている形式を紹介する。 計算しようとする対象が \[ \frac{P(0,N)}{Q(0,N)} = \sum_{n=0}^{N-1} \frac{a(n)}{b(n)} \frac{p(0)\cdots p(n)}{q(0)\cdots q(n)} \]
のような形になるよう、 適切な式 $P(l,u)$、$Q(l,u)$、$R(l,u)$ を設定する。 (具体例は下記) するとそれらの具体的計算については $l\le m\lt u$ となる $m$ を用いて以下のように再帰計算ができる。 $l+1=u$ となる場合は定義式($a(n)$ など)に $n=u$ を代入する。
\[ \begin{eqnarray} P(l, u) &=& P(l, m)Q(m, u) + R(l, m)P(m, u)\\ Q(l, u) &=& Q(l, m)Q(m, u)\\ R(l, u) &=& R(l, m)R(m, u) \end{eqnarray} \]このとき、$m\simeq \left\lfloor\dfrac{l+u}{2}\right\rfloor$ とすることで上記のような計算量に落ち着く。
具体例の引用として $\arctan(1/x)$ の計算をマクローリン展開計算を取る。 \[ \arctan\frac{1}{x} \simeq \frac{P(0,N)}{Q(0,N)} =\sum_{k=0}^{N-1}\frac{(-1)^k}{(2k+1)x^{2k+1}} \] \[ \Rightarrow \left\{ \begin{eqnarray} P(l, u) &=& R(l, u) \sum_{k=l}^{u-1} (-1)^{k+1} \frac{x^{u-1-k}}{2k+3}\\ Q(l,u) &=& x^{2(u-l)} \prod_{k=l}^{u-1}(2k+3)\\ R(l,u) &=& \prod_{k=l}^{u-1}(2k+3) \end{eqnarray} \right. \]
詳細版
BS 法は上記の形がよく知られているが、本来はより広範囲に適用できるアルゴリズムである。 [FT05]
求めようとする級数が \[ S = \sum_{n=0}^{\infty} \frac{a(n)}{b(n)} \frac{p(0)\cdots p(n)}{q(0)\cdots q(n)} \quad {\rm または}\quad U = \sum_{n=0}^{\infty} \frac{a(n)}{b(n)} \left(\frac{c(0)}{d(0)}+\cdots+\frac{c(n)}{d(n)}\right) \frac{p(0)\cdots p(n)}{q(0)\cdots q(n)} \]
の形で表わされているとする。このとき、この部分級数 \[ S = \sum_{n_1 \lt n\lt n_2} \frac{a(n)}{b(n)} \frac{p(n_1)\cdots p(n)}{q(n_1)\cdots q(n)} \quad {\rm または}\quad U = \sum_{n_1 \lt n \lt n_2} \frac{a(n)}{b(n)} \left(\frac{c(n_1)}{d(n_1)}+\cdots+\frac{c(n)}{d(n)}\right) \frac{p(n_1)\cdots p(n)}{q(n_1)\cdots q(n)} \]
を直接計算するのではなく $P=p(n_1)\cdots p(n_2-1)$、$Q=q(n_1)\cdots q(n_2-1)$、 $B=b(n_1)\cdots b(n_2-1)$、$D=d(n_1)\cdots d(n_2-1)$、 $C=D(c(n_1)/d(n_1)+\cdots+c(n_2-1)/d(n_2-1))$ を考えて $T=BQS$ や $V=DBQU$ を求めてから $S=R/BQ$ や $U=V/DBQ$ を導く。 $m=\lfloor(n_1+n_2)/2\rfloor$ として $n_1\leqq n\lt m$ に属する項を $B_l$、$P_l$、$Q_l$、$T_l$、$D_l$、$C_l$、$V_l$、 逆に $m\leqq n\lt n_2$ に属する項を $B_r$、$P_r$、$Q_r$、$T_r$、$D_r$、$C_r$、$V_r$、 とするとき
\[ B = B_lB_r,\ P = P_lP_r,\ Q = Q_lQ_r,\ T = B_rQ_rT_l + B_lP_lT_r \] \[ D = D_lD_r,\ C = C_lD_r + C_rD_l,\ V = D_rB_rQ_rV_l + D_rC_lB_lP_lT_r + D_lB_lP_lV_r \]で再帰的に計算する。 また以下のような C++ によるサンプルコード(コメント部分は日本語訳)も掲載されている。[FT05]
// S を計算する方 // ユーザーが初期値を入れるものとする struct { bigint *a, *b, *p, *q; } abpq_series; // 分数の形で結果を保持する struct { bigint P, Q, B, T; } abpq_series_result; // Binary Splitting による計算 void sum_abpq(abpq_series_result& r, int n1, int n2, const abpq_series& arg) { switch(n2 - n1) { // 級数の長さで分類 case 0: error_handler("summation devide", "n2-n1 should be > 0."); break; case 1: // the result at the point n1 r.P = arg.p[n1]; r.Q = arg.q[n1]; r.B = arg.b[n1]; r.T = arg.a[n1] * arg.p[n1]; break; // case 2, 3, 4 は簡略化のため省略 default: // 一般の場合 abpq_series_result L, R; int nm = (n1 + n2) / 2; sum_abpq(L, n1, nm, arg); sum_abpq(R, nm, n2, arg); r.P = L.P * R.P; r.Q = L.Q * R.Q; r.B = L.B * R.B; r.T = R.B * R.Q * L.T + L.B * L.P * R.T; break; } }
// U を計算する方 // ユーザーが初期値を入れるものとする struct { bigint *a, *b, *p, *q, *c, *d; } abpqcd_series; // 分数の形で結果を保持する struct { bigint P, Q, B, T, C, D, V; } abpqcd_series_result; // binary splitting による計算 void sum_abpqcd(abpqcd_series_result& r, int n1, int n2, const abpqcd_series& arg) { switch(n2 - n1) { // 級数の長さで分類 case 0: error_handler("summation devide", "n2-n1 should be > 0."); break; case 1: // the result at the point n1 r.P = arg.p[n1]; r.Q = arg.q[n1]; r.B = arg.b[n1]; r.T = arg.a[n1] * arg.p[n1]; r.C = arg.c[n1]; r.D = arg.d[n1]; r.V = arg.a[n1] * arg.c[n1] * arg.p[n1]; break; // case 2, 3, 4 は簡略化のため省略 default: // 一般の場合 abpqcd_series_result L, R; int nm = (n1 + n2) / 2; sum_abpqcd(L, n1, nm, arg); sum_abpqcd(R, nm, n2, arg); r.P = L.P * R.P; r.Q = L.Q * R.Q; r.B = L.B * R.B; bigint tmp = L.B * L.P * R.T; r.T = R.B * R.Q * L.T + tmp; r.D = L.D * R.D; r.C = L.C * R.D + R.C * L.D; r.V = R.B * (R.B * R.Q * L.V + L.C * tmp) + L.D * L.B * L.P * R.V; break; } }
各関数に対応する項
上記の形で書かれても今一つ項が見えない…というより分かりづらいので
[FT05] 中にある項を表にまとめてみた。
表の中に現れる変数 $x$ は有理数で $x=u/v$ と表されるものとする。
また、$p(n)$ や $q(n)$ は $n=0$ で特殊な値を取ることが多いので別項を立てたが、
一般項で記述可能な場合は -
を入れている。
$f(x)$ | $a(n)$ | $b(n)$ | $p(0)$ | $q(0)$ | $p(n)$ | $q(n)$ | 備考 |
---|---|---|---|---|---|---|---|
$\exp(x)$ | 1 | 1 | 1 | 1 | $u$ | $nv$ | |
$\ln(1+x)$ | 1 | $n+1$ | $u$ | - | $-u$ | $v$ | |
$\sin(x)$ | 1 | 1 | $u$ | $v$ | $-u^2$ | $2n(2n+1)v^2$ | |
$\cos(x)$ | 1 | 1 | 1 | 1 | $-u^2$ | $2n(2n-1)v^2$ | |
$\arctan(x)$ | 1 | $2n+1$ | $x$ | - | $-x^2$ | 1 | 何故か $u$、$v$ を使った形で与えられてない |
$\dfrac{\sqrt{C}}{12\pi}$ | $A+nB$ | 1 | 1 | 1 | $-(6n-5)(2n-1)(6n-1)$ | $n^3C/24$ | Chudnovskyの公式。 各定数はリンク先と一緒。 |
カタラン数 $G$※1 | 1 | $2n+1$ | 1 | 1 | $n$ | $4n+2$ | ※1 |
$2\zeta(3)$ ※2 | $205n^2+250n+77$ | 1 | 1 | - | $-n^5$ | $32(2n+1)^5$ |
- ※1 $G=\dfrac{3}{8}{\displaystyle \sum_{n=0}^{\infty}}\dfrac{1}{\left(2n \atop n\right)(2n+1)^2}+\dfrac{\pi}{8}\log(2+\sqrt{3})$ の $\sum$ 部分だけを求めている。