개요
FFT는 이산적인 영역에서 하는 푸리에 변환인 DFT(Discrete Fourier Transform)을 분할정복 기법을 이용하여
DFT (Discrete Fourier Transform)
우선 DFT의 정의부터 살펴봅시다. 수열
사실 이 정의가 뜻하는 바는, 같은 수열에 대해 다항식,
그럼 이걸 가지고 뭘 할 수 있을까요?
우선 두 다항식의 곱셈에 대한 문제를 생각해봅시다.
다항식
왜냐하면
그렇다면 만약 역변환인 IDFT(Inverse Discrete Fourier Transform)을 취할 수 있으면(IDFT에 대한 설명은 나중에 나옵니다),
두 다항식을 곱한 결과값을 구할 수 있게 됩니다.
즉,
하지만 문제가 있는데, DFT를 정의대로 계산하면,
여기서 우리는 DFT를
FFT(Fast Fourier Transform)
DFT를 빨리 계산하기 위해서 우리는 우함수와 기함수의 성질을 이용합니다.
짝수 차수만 있는 우함수
그렇다면
가 성립하기 때문에,
위에서 설명했던 DFT로 돌아가자면,
을 알 수 있습니다.
단 이 방식이 재귀적으로 적용되기 위해서는 다항식의 길이가 2의 거듭제곱 꼴 이어야합니다. 그럼으로 부족한 만큼 0을 추가해주면 됩니다.
그럼 우리는 FFT를
파이썬 코드를 살펴보자면,
def fft(p, w):
n = len(p)
if n == 1: #Base Case
return p
even, odd = p[0::2], p[1::2] #짝수차수와 홀수차수로 분할
yeven, yodd = fft(even, w*w), fft(odd, w*w) #재귀적으로 불러옴 w*w인 이유는 w^2가 들어가기 떄문에
z = complex(1, 0)
y = [0] * n
for j in range(n//2): #위에서 구한 공식
y[j] = yeven[j] + z * yodd[j]
y[j + n//2] = yeven[j] - z * yodd[j]
z *= w
return y
IDFT(Inverse Discrete Fourier Transform)
이것이 왜 성립하는지 잘 이해가 가지 않을 수 있는데,
이 행렬곱은 N = 4일때 DFT의 정의와 정확히 일치하는것을 알 수 있습니다.
그렇다면 이 행렬의 역행렬은,
임이 자명합니다. 계산해보면 항등행렬이 나옵니다.
다항식 곱셈 파이썬 코드를 살펴봅시다.
def mult(a, b):
n = 1
while n <= len(a) and n <= len(b):
n *= 2
n *= 2 #다항식의 크기를 2의 거듭제곱꼴로 맞춰준다
a = a + [0] * (n - len(a))
b = b + [0] * (n - len(b))
w = complex(math.cos(2*pi/n), math.sin(2*pi/n)) #w계산
a = fft(a, w)
b = fft(b, w) #a, b다항식을 각각 fft 취해준다.
c = [0] * n
for i in range(n):
c[i] = a[i] * b[i] #fft의 결과값을 곱해준다.
c = fft(c, 1/w) #IFFT를 취해준다.
for i in range(n):
c[i] /= n
c[i] = round(c[i].real)
return c
'알고리즘' 카테고리의 다른 글
2023 02 21 problem solving (0) | 2023.02.21 |
---|---|
백준 1750 서로소의 개수 파이썬 (0) | 2023.02.19 |
2023 02 17 problem solving (0) | 2023.02.17 |
백준 25402 트리와 쿼리 파이썬 풀이 (1) | 2023.02.17 |
정올 1차 1, 2번 문제 풀이 (0) | 2023.02.16 |