Здесь мы рассмотрим листинг "fft2" сверху вниз, комментируя все детали.
Сверху вы видите фрагмент, совпадающий со старым листингом вплоть до #define M_2PI. Этот макрос
определяет константу 2π.
Функция complex_mul выполняет умножение комплексных чисел z1 и z2 и записывает
результат в ячейку z.
Мы собираемся вызывать алгоритм "fft" M раз для одного и того же числа элементов L.
Для оптимизации мы должны вынести за пределы алгоритма "fft" те действия, которые не зависят от выбора конкретных
элементов в массиве.
К таким действиям можно отнести выделение памяти для хранения поворачивающих множителей и освобождение ее.
Деление результата на N также можно выполнить позже для всего массива сразу. А главное, мы можем всего
лишь однажды вычислить все поворачивающие множители. Для решения этой задачи мы напишем отдельную функцию
createWstore, которая и вычисляет множители, и выделает массив ячеек памяти для них. Позднее этот
массив будет передаваться как параметр в новый вариант алгоритма "fft".
Функция createWstore представляет собой ту часть основного цикла "fft", которая отвечала за рассчет
поворачивающих множителей. Однако, она оптимизирована. Число итераций меньше, чем в исходном алгоритме,
поскольку не на всех итерациях выполнялось вычисление нового множителя, иногда происходило только копирование.
Поэтому шаг приращений индекса в массиве вдвое больше: Skew2 вместо Skew.
Переменная k для определения четности/нечетности нам больше не нужна, так что внутренний цикл
останавливается при достижении границы массива WstoreEnd.
Порядок вычисления множителей будет понятнее на примере. Если
L = 32, то порядок изменения k такой (точкой с запятой разделены итерации внешнего цикла,
а запятой - внутреннего):
Далее, вместо старого алгоритма "fft" мы напишем новый - "fft_step" с учетом того, что поворачивающие множители
считать не надо, и не надо делить результат на N.
Сам алгоритм практически не изменился за исключением того, что все расстояния между элементами
массива увеличились в M раз, согласно формуле (38). Приставка "M" перед именами
новых переменных означает умножение на M.
На вход этой функции будет передаваться массив со смещением. Тем самым происходит коррекция индекса
на +h элементов, согласно формуле (38).
В основной функции сначала анализируется параметр N. Если он нечетный, то мы вынуждены отсечь
один элемент (последний) и уменьшить N на единицу. Таким образом, на входе алгоритма требуется
N ≥ 2.
Далее вычисляется L как максимальная степень двойки, кратная N, сама эта степень
T и величина M.
Затем вычисляются поворачивающие множители для "fft_step" и вызывается сам "fft_step" нужное число раз. Если
оказывается, что N является степенью двойки, то сработает обычный "fft".
Следующим шагом мы вычисляем поворачивающие коэффициенты уже для формулы (40). Этот фрагмент алгоритма очень
похож на createWstore, поэтому в дополнительных комментариях не нуждается. Результат оказывается
в массиве mult.
Далее вычисляется формула (40). Смысл переменных: pX - указатель на Xr+sL;
rpsL = r + sL; mprM = m + rM; one - очередное слагаемое суммы (40).
Величина widx равна остатку от деления m(r + sL) на N. Таким способом
мы избегаем выхода за границы массива mult. Это можно делать, благодаря Теореме 1 - ведь
поворачивающие множители как раз имеют период N.
Еще можно заметить, что в сумме (40) в первом множителе поворачивающий коэффициент всегда равен 1,
благодаря чему мы экономим несколько умножений.
И наконец, происходит корректировка результатов для обратного ДПФ делением на N.
Знаете ли Вы, что "гравитационное линзирование" якобы наблюдаемое вблизи далеких галактик (но не в масштабе звезд, где оно должно быть по формулам ОТО!), на самом деле является термическим линзированием, связанным с изменениями плотности эфира от нагрева мириадами звезд. Подробнее читайте в FAQ по эфирной физике.