ضرب چندجملهایها با FFT
دو چندجملهای را در O(n log n) ضرب میکند: هر دو را در ریشههای واحد ارزیابی میکند، مقدارها را نقطه به نقطه ضرب میکند و با FFT وارون ضریبها را برمیگرداند.
ضرب مستقیم دو چندجملهای درجهی n (هر ضریب در هر ضریب) O(n²) است. ولی چندجملهای را میشود با مقدارهایش در n نقطه هم نشان داد، و در این نمایش ضرب فقط O(n) است: مقدارها را نقطه به نقطه ضرب کن.
- زمان:
O(n log n) - حافظه:
O(n) - CLRS، بخش ۳۰.۱
(1 + 2x + 3x²)(4 + 5x) = 4 + 13x + 22x² + 15x³؛ ضریبها از توان صفر شروع میشوند.
import cmathdef multiply(A, B):# Coefficients, lowest power first: [a_0, a_1, …].a, b = A[0], B[0]size = len(a) + len(b) - 1n = 1while n < size:n = n * 2fa = fft(a + [0] * (n - len(a)), False)fb = fft(b + [0] * (n - len(b)), False)fc = [x * y for x, y in zip(fa, fb)]c = fft(fc, True)product = [round((v / n).real) for v in c][:size]return productdef fft(a, inverse):n = len(a)if n == 1:return [complex(a[0])]sign = -1 if inverse else 1w_n = cmath.exp(sign * 2j * cmath.pi / n)even = fft(a[0::2], inverse)odd = fft(a[1::2], inverse)y = [0] * nw = 1for k in range(n // 2):t = w * odd[k]y[k] = even[k] + ty[k + n // 2] = even[k] - tw = w * w_nreturn y
شروع اجرا
A
| 1 | 2 | 3 |
B
| 4 | 5 |
درخت فراخوانیهای بازگشتی
نارنجی پر = فراخوانی در حال اجرا · حاشیهی نارنجی = هنوز روی پشته · خاکستری = تمام شده
متغیرهای محلی
نارنجی = در همین گام عوض شد
A list
B list
Call stack
- multiply()خط 4
توضیح
ایده
ضرب مستقیم دو چندجملهای درجهی n (هر ضریب در هر ضریب) O(n²) است. ولی چندجملهای را میشود با مقدارهایش در n نقطه هم نشان داد، و در این نمایش ضرب فقط O(n) است: مقدارها را نقطه به نقطه ضرب کن.
سه گام
- ارزیابی: هر دو چندجملهای را با FFT در
nریشهی واحد حساب کن (nتوان ۲ای که برای حاصلضرب کافی است):O(n log n). - ضرب نقطهای:
O(n). - درونیابی: با FFT وارون ضریبهای حاصلضرب را برگردان:
O(n log n).
جمعاً O(n log n). چون عددهای میانی مختلطاند، ضریبهای نهایی را به نزدیکترین عدد صحیح گرد میکنیم.
در trace به چه چیزی نگاه کنی
- درخت فراخوانی سه FFT را نشان میدهد؛
productضریبهای نهایی از توان صفر به بالاست.