如何調試fft與ntt

FFT(快速傅里葉變換)/NTT(數論變換)是卷積運算常見而實用的優化

但是FFT/NTT的處理過程並不像暴力運算(差不多是多項式乘法)那樣能夠直觀地反映卷積結果的實時變化。

因此在使用FFT時將會或多或少地加大調試的難度。

如果調試程序時直接跟蹤變量,每步手算結果比對,不僅會耽誤大量時間,而且效果可能並不理想。

直接肉眼查錯效率可能也不太高。

但也正由於FFT的特點,實際上也有一些很方便而實用的調試方法,能夠明顯提升調試的效率,減小調試難度。

一 、暴力卷積 確定算法

先寫好一個能解決題目問題的程序,只不過求解卷積的過程使用暴力來實現

或許這一步看上去是很浪費時間的,但是這一步也是很有用的
在做着一步時,我們可以將思維的重點放在建模和模型變換上。建模也是寫完 FFT模板之後必做的過程,在這一開始就做好建模不僅可以減少打好FFT模板之後的思考複雜度和緊張感,而且也便於直觀地發現和更正模型的錯誤。

如果在這一步就確定了卷積算法不可行,那麼就之後就不用再寫FFT多走彎路
如果在這一步確定的卷積算法的正確性,那麼在之後程序出錯時,我們就可以大膽地排除算法的錯誤性,將調試的重點放在FFT模板上。
這一步寫好的程序還可以在後面用來對拍

在比賽中,如果花了不短的時間寫好了FFT模板,結果發現套用卷積算法並沒有想象中的那麼簡單,甚至卷積根本就解決不了題目。那麼這時整個人肯定都不太好受吧。。。
爲了比賽打得穩,最好還是先寫一個卷積暴力。

如果不想寫暴力卷積代碼,其實我們還可以直接暴力手算卷積,看能不能得出樣例的結果

怎麼方便地手算呢?
機械地執行卷積代碼..?

直接模仿豎式乘法,將兩個輸入數組移位相加就好啦

二 、分段查錯 快速定位

在平常的調試中,時間肯定會浪費在正確代碼的檢驗上
而如果程序比較長,我們可能還會在定位錯誤的位置中耽誤很多時間

因此爲了調試過程的高效快速
調試時就可以縮小調試的範圍
直接依次檢測每一個具有完整功能的子程序的錯誤

三 、輸出調試 驗證模板

我們甚至可以在寫代碼時每寫好一段就輸出運算結果,進一步提升寫題的效率

而FFT的特性也方便我們寫FFT模板時的分段輸出調試

0檢查曾經寫錯的代碼,關鍵代碼是否寫錯 數組大小是否足夠
1檢查位數n,模數p=kn+1,次數ci,原根g,n的逆元(乘n是否爲1)是否正確
3接着檢查n次單位根w是否正確
怎麼檢查呢..?直接檢查w[1]^n是否爲1就好啦
4檢查二進制反序的處理是否正確
打好模板了,上面這些關鍵部分都沒問題,但這樣還不能保證FFT完全無錯
接下來的操作挺簡單而有用的,通過了這個驗證則說明FFT很可能無錯
5先將要進行多項式乘法數組a的DFT,再求出這個結果的逆DFT,觀察是否等於a本身

接下來還可以和之前寫的暴力程序對拍,保證程序的正確性

四 、補充

FFT用到了對中學生來說相對高深的數學知識

如果不能弄懂原理死記硬背起來應該相當麻煩

那麼有什麼記模板的方法呢..?
1最主要的還是要弄懂原理,理解算法。可以嘗試補充學習一些數學知識和閱讀一些相關論文
2記錄下模板的要點
大致弄清有幾個部分 有幾層循環 每一部分大致要做什麼
3 多寫模板,並且總結容易寫錯的地方
4 編一些有趣的口訣記憶

做題時常用的方法:

1答案對小素數取模,且n的數量級在10^5時,可以直接進行FFT,然後將結果加上eps後進行取整操作
2答案對大素數取模,若大素數(約10^9數量級)爲二的冪的若干倍+1(kn+1),那麼可以直接進行NTT
如果大素數不是kn+1的形式
那麼可以選取3個合適的爲kn+1形式的素數,然後分別求解答案
再使用中國剩餘定理求得模原大素數的答案

發佈了193 篇原創文章 · 獲贊 9 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章