聊聊 fft 的单位根

与 ntt 不同,计算 fft 的单位根更复杂,要考虑精度问题.

关于fft精度的一点事实 fft精度比暴力dft高得多.

原因主要是fft可以算作一种成对求和.

对fft精度的严格分析往往比经验精度要低很多.

原因有很多,比如实践中误差很难都同向舍入.

三次变两次(尤其在值域差距大时)精度误差较大.(三次变一点五次基本无此问题.)

可以认为直接从三角函数计算出的单位根精度是最高的.

由于 \(\sin(x)\)\(\cos(x)\) 精度几乎无可指摘(仅仅不保证尾数的最后一位).

但传入幅角的精度有限制,因此 long double 计算再转 double 有意义(如果 long double 精度好于 double).

全部使用三角函数计算比较昂贵.(相对复数乘法而言,三角函数是相当慢的,尽管用三角恒等式精细实现只需要算 \(\dfrac{n}{4}\) 次.)

ps : 常见的 fft 写法对单位根做了 \(n\) 次乘法,可谓精度飞天.

可以考虑只计算 \(\log n\) 个单位根然后用乘积组合出剩下的单位根.

比如可以计算 \(2^k\) 次本原单位根然后二进制组合.

这样只有 \(\log n\) 次乘法(对于使用的单位根来说),是一种不错的办法.

参见 https://loj.ac/s/2005800

这个思想是可以在线计算单位根而无需预处理出 \(O(n)\) 量级的表的.

参见 https://loj.ac/s/2005807

另一个办法是用光速幂的思路.

计算 \(\sqrt n\) 个单位根然后用乘积组合出剩下所需的单位根.

这样只有 \(1\) 次乘法,可维持相当高的精度.

参见 https://loj.ac/s/2005809

用这个思想在线计算是很简单的,直接做即可.

参见 https://loj.ac/s/2005850

常规来说,在线计算意义并不大(往往变慢),但有些时候在线计算单位根能更好的利用 cache 从而减少常数.(尤其是变换长度极大时)

最后放一下一个对精度要求较高的题目,可以自行测试.

https://judge.yosupo.jp/problem/convolution_mod_1000000007

使用根号预处理(或者完全预处理)是可以用double跑过的,其他方式都比较困难.

参见 https://judge.yosupo.jp/submission/191165

这些提交都是 dif/dit 并利用 \(conj(w)=\dfrac{1}{w}\) 以不计算逆单位根或翻转.

posted @ 2024-02-17 15:45  QedDust  阅读(201)  评论(0)    收藏  举报