У меня есть немного кода на C++, который со временем стал довольно полезной библиотекой БПФ, и он был сделан для достаточно быстрой работы с использованием инструкций SSE и AVX. Конечно, все это основано только на алгоритме счисления по основанию 2, но он все еще работает. Последнее, что мне не терпится поцарапать, — заставить вычисления бабочки работать с инструкциями FMA. Базовая бабочка по основанию-2 состоит из 4 умножений и 6 сложений или вычитаний. Простой подход будет включать замену 2 операций сложения и вычитания и 2 операций умножения двумя инструкциями FMA, в результате чего получится математически идентичная бабочка, но, по-видимому, есть и лучшие способы сделать это:
ci1 = ci1 / cr1
u0 = zinr(0)
v0 = zini(0)
r = zinr(1)
s = sini(1)
u1 = r - s * ci1
v1 = r * ci1 + s
zoutr(0) = u0 + u1 * cr1
zouti(0) = v0 + v1 * cr1
zoutr(1) = u0 - u1 * cr1
zouti(1) = v0 - v1 * cr1
Автор заменяет все 10 добавлений, сабвуферов и мультов на 6 FMA при условии, что мнимая часть фактора поворота делится на действительную часть. Часть текста гласит: «Обратите внимание, что cr1 != 0». Это, по сути, моя проблема в двух словах. Кажется, что математика работает точно так же, как рекламируется, для всех коэффициентов оборота, за исключением случаев, когда реальный оборот равен нулю, и в этом случае мы заканчиваем делением на ноль. Там, где эффективность здесь абсолютно критична, код ветвления, когда cr1 == 0, к другой бабочке не является хорошим вариантом, особенно когда мы используем SIMD для одновременной обработки нескольких твиддлов и бабочек, где, возможно, только один элемент cr1 == 0. Моя интуиция говорит мне, что это должно иметь место, так это то, что когда cr1 == 0, cr1 и ci1 должны быть совершенно другими значениями, и код FMA все равно приведет к правильному ответу, но я не могу понять это . Если бы я мог понять это, было бы относительно просто изменить предварительно вычисленные коэффициенты поворота для бабочек FMA, и мы также, конечно, могли бы избежать операции деления в начале бабочки.