题解 P5432/基于科学计数法的 FFT 优化高精

· · 题解

可能更好的阅读体验

本文将介绍基于科学计数法的方法,使用 FFT 优化高精度除法、开根、指数、对数等。

对于多项式

f(x)=f_0+f_1x+f_2x^2+f_3x^3+\cdots

对于高精度整数,通常是将其表示为 f(10) 的形式,如

3579=9+7\times 10+5\times 10^2+3\times 10^3

但这一方法不能较好地表示小数。

考虑科学计数法,将每个数表示为 f(10^{-1})\times10^n 的形式,如

158.97=1.5897\times 10^2 =(1+5\times 10^{-1}+8\times 10^{-2}+9\times 10^{-3}+7\times 10^{-4})\times 10^2

由此我们得到了高精度小数的表示方法。

高精度小数的乘法

(f(10^{-1})\times 10^n)\times(g(10^{-1})\times 10^m)=(f\times g)(10^{-1})\times 10^{n+m}

FFT 优化即可,注意进位跟整数是反过来的。

高精度小数的倒数

对于高精度整数,求倒数显然是不可能的。

但高精度小数可以,根据多项式求逆:

a(x)f(x)\equiv 1\pmod{x^n} a(x)\equiv 1\pmod{x^{\frac{n}{2}}} f(x)\equiv g(x)(2-a(x)g(x))\pmod{x^n}

但我们无法使用多项式求逆的终止条件 (a_0f_0=1)
考虑将同余式展开并代入

A=a(10^{-1}),F=f(10^{-1}),G=g(10^{-1}) AF=1-10^{-n}C_0,C_0\in[0,1) AG=1-10^{-\frac{n}{2}}C,C\in[0,1) 1-2AG+A^2G^2=10^{-n}C^2,C^2\in[0,1) F^2-2FG+G^2=(1-10^{-n}C_0)10^{-n}C,C\in[0,1) F=G(2-AG)-10^{-n}C,C\in[0,1)

选择 [0,1) 而非 [0,10) 是为了避免进位的情况。

终止条件是 n=2,此时 F=10^{-1}{\left\lfloor\dfrac{100}{10a_0+a_1}\right\rfloor}

高精度小数的除法

\dfrac{f(10^{-1})\times 10^n}{g(10^{-1})\times 10^m}=f(10^{-1})g^{-1}(10^{-1})\times 10^{n-m}

计算出 f(10^{-1})g^{-1}(10^{-1}) 即可。

整除保留整数即可,可能有 1 的误差,需要作出调整。

可以发现,这一做法跟多项式除法“先翻转再求逆”的方法是一致的,
实际上体现了多项式除法的直观意义。

高精度开根

开根可以使用牛顿迭代法计算

x^2-a=0 x=\dfrac{x_0}{2}+\dfrac{a}{2x_0}

每迭代一次精度翻倍,结合倍增可以 \Theta(n\log n) 求出。

高精度 ln 和 exp

与多项式 ln 和 exp 不同的是,\ln f(x)=\displaystyle\int^x\dfrac{f'(t)}{f(t)}\mathrm{d}t 没法用了。

这里搬一下 WC2012《理性愉悦: 高精度数值计算》中的原内容,对于数列

a_0=a,b_0=b,a_{n+1}=\dfrac{a_n+b_n}{2},b_{n+1}=\sqrt{a_nb_n}\quad(n\in \mathbf{N})

\displaystyle \lim_{n\rightarrow\infty}a_n=\lim_{n\rightarrow\infty}b_n=\dfrac{\pi}{2}{\left(\int_0^{\frac{\pi}{2}}\dfrac{\mathrm{d}x}{\sqrt{a^2\cos^2x+b^2\sin^2x}}\right)}^{-1}
且跟牛顿迭代一样误差是平方级别的缩小。

称这一极限为 a,b算术几何平均数,记为\operatorname{AG}(a,b) 。它有如下性质:

\forall x\ge 4,{\left|\dfrac{\pi}{2\operatorname{AG}{\left(1,\dfrac{4}{x}\right)}}-\ln x\right|}\le\dfrac{64}{x^2}{\left(8+\ln\dfrac{x}{4}\right)} $$\lim_{n\rightarrow\infty} \dfrac{4a_n^2}{1-\displaystyle\sum_{k=0}^n2^k(a_k-b_k)^2}=\pi$$ 同样误差是平方级别的缩小。 对于较大的 $x$,可以通过计算 $\dfrac{\pi}{2\operatorname{AG}{\left(1,\dfrac{4}{x}\right)}}$ 达到 $\lfloor\log_{10}x\rfloor$ 的精度。 对于较小的 $x$, - 若 $x>1$,可以通过 $\ln x=\dfrac{1}{2}\ln x^2$ 放大 $x$ 来提高精度。 - 否则,计算出 $\ln 10$ 后,通过 $\ln x=\ln (10^mx)-m\ln 10$ 提高精度。 时间复杂度 $\Theta(n\log^2 n)$。 有了 ln 后,exp 也就可用牛顿迭代求得。 ## 总结 相比于仅仅是将整数换为小数,就能更有效地解决乘除、开根一类的问题。 由此可见,看待问题的角度,有时比解决问题的方法更为重要。