FFT / NTT / FWT 연구 노트

최근 보트 투어 배 미친, 좋은 기분 ~

FFT


 

고속 푸리에 변환 (FFT)

특정 파생이 참조 : 후 토끼 - 학생들이 FFT를 이해할 수있다! ! !  (물론 쓰기,하지만이 처음으로 학생들은 0.0 이해하지 못했다)

핵심 요소를 요약

 

~ 제 1 부 ~ 다항식 피벗 포인트 값을 나타냅니다

$ 2 전원 원래 다항식 $ A는 (X) $ $으로 보완 재귀 분할 하였다

즉, 현재 레이어의 $ 다항식 B (x)는 $, $ N $의 숫자로 설정한다 : $ B를 (X) = + b_0 B_ {1}, X + B_ {2} X ^ {2} + ... + B_ {N-1}, X ^ {N-1} $

이것은 제 패리티 계수에 따라 두 다항식으로 분할

\ [B_0 (X) = b_0 + + b_2x b_4x ^ 2 + ... + B_ {N-2} X ^ {\ FRAC {N} {2} -1} \]

\ [B_1 (X) = B_1 b_3x + + b_5x ^ 2 + ... + B_ {N-1}, X ^ {\ FRAC {N} {2} -1} \]

이것은 $ B 일 수있다 (X)는 $ 재 나타낸다 : $의 B (X) = B_0 (X ^ 2) + xB_1 (X ^ 2) $

우리는 복소 평면 대입 포인트 단위 원은 $의 B를 (\ 오메가 ^ {1} _ {N}) $, ..., $ B (\ 오메가 ^ {N} _ {N}) $ 값을 부여 할

때문에 단위 원에 $ \ 오메가 $이므로 $ \ 오메가 ^ 2051-N \ cdot \ 오메가 ^ j_n = \ 다음 $ 0 \ 당량 I <\ FRAC {N} {2} $ 거기 [여기 복잡한 연산 법을 사용하는 경우 오메가 ^ _n $ {난 J +} $ 2 $에서 $ N- $ 배수이므로 $ \ 오메가 ^ 2051-N = \ 오메가 ^ {\ FRAC {I}를 {2}} _ {\ FRAC {N} {2} } $]

\ 시작 B (\ 오메가 ^ 2051-N) = B_0 {* 정렬} ((\ 오메가 ^ 2051-N) ^ 2) + \ 오메가 ^ i_nB_1 ((\ 오메가 ^ 2051-N) ^ 2) \\ & = B_0 (오메가 \ ^ {2I} _n) + \ 오메가 ^ i_nB_1 (\ 오메가 ^ {2I} _n) \\ & = B_0 (오메가 \ ^ 제가 _ {\ FRAC {N} {2}}) + \ 오메가 ^ i_nB_0 (\ 오메가 ^ I_ {\ FRAC {N} {2}}) \ 단부 {} * 정렬

단위 원에 나머지 절반 후 별도로 여기 [복잡한 연산 법이있다 : $ N- $는 $의 $ 2의 배수이기 때문에 너무 $ \ 오메가 ^ {내가 + \ FRAC {N} {2}} _ N = - \ 오메가 ^ $ 2051-N]

\ 시작 {정렬 *} B (\ 오메가 ^ {내가 + \ FRAC {N} {2}} _ N) = B_0 ((\ 오메가 ^ {내가 + \ FRAC {N} {2}} _ N) ^ 2) + \ 오메가 ^ {난 + \ FRAC {N} {2}} _ nB_1 ((\ 오메가 ^ {I + \ FRAC {N} {2}} _ N) ^ 2) \\ & = B_0 (\ 오메가 ^ {2I + N} _n ) - \ 오메가 ^ i_nB_1 (\ 오메가 ^ {2I + N} _n) \\ & = B_0 (오메가 \ ^ I _ {\ FRAC {N} {2}}) - \ 오메가 ^ i_nB_0 (\ 오메가 ^ I _ {\ FRAC {N} {2}}) \ 단부 {} * 정렬

이 층은 우리가 $ B를 계산 (\ 오메가 ^ 0_n)은 $, ..., $ B는 (\ 오메가 ^ {N-1} _는 {N-1}) $ $ B_0는 문제가 산출 한진다 (\ 오메가 ^ 0 _ {\ FRAC {N} {2}}) $, ..., $ B_0 (\ 오메가 ^ {\ FRAC {N} {2} -1} _ {\ FRAC {N} {2} }) $, $ B_1 (\ 오메가 ^ 0 _ {\ FRAC {N} {2}}) $, ..., $ B_1 (\ 오메가 ^ {\ FRAC {N} {2} -1} _ {\ FRAC {N} {2}}) $

따라서, 총 복잡도는 $ O (N logN)은 $

 

다항식의 ~ 2 부 ~ 소수점 값 전달 계수

$ 여러 원시 다항식 설정하면 A (X) = a_0 + + a_1x a_2x ^ 2 + ... + A_ {N-1}, X ^ {N-1} $, $ 2 $ 11 항에있어서, 용어의 전력으로서 $ n 개의 $

각각 $ \ 오메가로 치환 ^ 0_n $, $ \ 오메가 ^ 1_n $, ..., 오메가 $ \ ^ {N-1} _n $, GET $ y_i = A (\ 오메가 ^ 2051-N) $, $ I = 0 1, ..., N-1 $, $, 즉 N- 포인트 값 $ 상기에서 얻어진

令 $ B (X) = + y_0 y_1x y_2x + ^ 2 + ... + Y_ {N-1}, X ^ {N-1} $

오메가 \ ^ - {1} _n $, ..., $ {- (N-1)} 다음 $ \ 오메가 ^ 0_n $, $ \ 오메가 ^로 치환 하였다 _ N $으로 계산 (생략)을 수득 $ A_I = \ FRAC {B (\ 오메가 ^ {- I} _n)} {N} $, $ I = 0,1, ..., N-1 $

 

다음의 코드에 따라이 아이디어는 (다항식 계수 뒤쪽 다항식 계수를 달성하기 위해 피벗 포인트 등) 작성된

지표의 갱스터 배열은 정말 편리한 사용

#INCLUDE <cstdio> 
#INCLUDE <복합체> 
#INCLUDE <cmath> 
#INCLUDE <CString을> 
#INCLUDE <알고리즘>
 사용  스페이스 성병; 

복합 타입 정의 < 더블 > CP;
CONST의  INT의 N = 100005 ;
CONST  이중 PI ACOS = (- 1.0 ); 

인라인 CP 오메가 ( INT의 X, INT의 N, INT의 REV) 
{ 
    경우 (REV) 
        X = - (X);
    리턴 CP (COS (X * 2 * 파이 / (이중 ) N), 죄 (X * 2 * PI / ( 더블 ) N)); 
} 

CP의 TMP [N]; 

보이드 FFT (CP * A, int로 N, INT의 REV) 
{ 
    경우 (N == 1 )
         복귀 ; 
    
    위한 ( int로 I = 0 ; I <N은, 내가 ++ ) 
        TMP가 [I] = A [I];
    위한 ( int로 난 = 0 ; i가 N / < 2 ; i가 ++ ) 
    { 
        A [I]를 TMP가 = [내가 * 2 ]; 
        A [N / 2 + i가] = TMP [내가 *2 + 1 ]; 
    } 
    
    FFT (a, N / 2 , REV); 
    FFT (a + N / 2 , N / 2 , REV); 
    
    위한 ( int로 난 = 0 ; i가 N / < 2 ; i가 ++ ) 
    { 
        CP X = 오메가 (I, N, 레브); 
        TMP [내가] = A [i]는 + X * A [N / 2 + I]; 
        TMP는 [N / 2 + i가] = A [i]를 -x * A [N / 2 + I]; 
    } 
    
    에 대해 ( int로 I = 0 ; I <N은, 내가 ++ ) 
        A [i]를= TMP [I]; 
} 

int로 N; 
A [N] CP; 

INT 의 main () 
{ 
//     freopen을 ( "input.txt를", "R", 표준 입력); 
    scanf와 ( " %의 D ' , N);
    위한 ( int로 I = 0 ; I <N이 나 ++ ) 
    { 
        INT (X)를; 
        scanf와 ( " %의 D ' , X); 
        A [I] = CP (( 더블 ) X, 0 ); 
    } 
    
    INT SZ = 1 ;
    반면 (SZ < N) 
        SZ<< = 1 ; 
    N = SZ; 
    
    FFT (a, N, 0 ); 
    FFT (a, n은, 1 ); 
    
    위한 ( int로 I = 0 ; I <N이 나 ++ ) 
        의 printf를 ( " %의 .2lf " , A [i]를 .real () / ( 더블 ) N)을; 
    의 printf ( " \ n을 " );
    반환  0 ; 
}
코드보기

 

~ 3 부 ~ 두 가지 간단한 최적화

비 재귀 :

제 1 부분의 순환, 즉 직접 수행에 $ A [i]를 $ 패리티 패킷 교환

여기서 과거 위치이다 이백이십일쌍 결국 $ 1 $ ($ $ 001)와 상호 교환 적으로 사용되는 경우, N = $ 8 $은 $ 4 $ ($ $ 100) -이 중

즉 두 진 절환 위치는 전후 반전

$ tmp를 [I] $ 배열 분리 :

각각 $ I $위한 순환 루프의 두 번째 부분 만 TMP가 [I]가 $, TMP 달러 $를 사용하여 [N / 2 + i]는 $는 A [N / A [I]을 $ $ $ 2 + I] $

그래서 현재 $ I $를 변경하지 아니 후 효과 대신 $ TMP의 임시 변수를 사용하는 것을 고려 [I] $ 배열

 

따라서,이 재귀하지 않고 기록 할 수 있고, $ TMP [I] $ 배열 FFT $ () 함수 $

보이드 FFT는 CP (* a는, int로 , N 의 INT 레브) 
{ 
    위해 ( int로 I = 0 ; I <N은, 내가 ++ ) 
    { 
        INT를 NXT = 0 ;
         ( INT의 J = 1 ; J <= N; J << = 1 )
             의 경우 (I 및 J) 
                NXT + = N / 2 / J; 
        
        경우 (NXT> I) 
            스왑 (a [i]를, A [NXT]); 
    } 
    
    에 대해 ( int로 난 = 2 ; i가 N = <나는 << = 1 )
         ( INT의 J = 0 ; J <J + N = I)
              ( INT에서 K = 0 ; K <입 / 2 ; ++ 케이 ) 
            { 
                CP X = 오메가 (K, I, REV); 
                CP의 B0 B1 = A [J + K] = A [i가 / 2 + J + K]; 
                A [J + K] = B0가의 + X * B1; 
                A [내가 / 2 + J + K]는 B0-X에서의 * = B1 단계; 
            } 
}
코드보기

 

FFT 컨볼 루션 계산

(계속 예정)

추천

출처www.cnblogs.com/LiuRunky/p/FFT_NTT_FWT.html