首页 > 解决方案 > 你将如何优化这个矢量化的谐波总和?

问题描述

我正在使用矢量化(仅 SSE2 max 作为 SIMD)将一组谐波相加,每个谐波具有不同的相位/幅度。

这是我的实际尝试:

float output = 0.0f;
simd::float_4 freqFundamentalNormalized = freq * (1.0f / sampleRate);
simd::float_4 harmonicIndex{1.0f, 2.0f, 3.0f, 4.0f};
simd::float_4 harmonicIncrement{4.0f, 4.0f, 4.0f, 4.0f};

// harmonics
const int numHarmonicsV4 = numHarmonics / 4;
const int numHarmonicsRemainder = numHarmonics - (numHarmonicsV4 * 4);

// v4
for (int i = 0; i < numHarmonicsV4; i++) {
    // signal
    simd::float_4 sineOutput4 = simd::sin(mPhases4[i] * g2PIf) * mMagnitudes4[i];

    for (int v = 0; v < 4; v++) {
        output += sineOutput4[v];
    }

    // increments
    mPhases4[i] += harmonicIndex * freqFundamentalNormalized;
    mPhases4[i] -= simd::floor(mPhases4[i]);

    harmonicIndex += harmonicIncrement;
}

// remainder
if (numHarmonicsRemainder > 0) {
    // signal
    simd::float_4 sineOutput4 = simd::sin(mPhases4[numHarmonicsV4] * g2PIf) * mMagnitudes4[numHarmonicsV4];

    for (int v = 0; v < numHarmonicsRemainder; v++) {
        output += sineOutput4[v];
    }

    // increments
    mPhases4[numHarmonicsV4] += harmonicIndex * freqFundamentalNormalized;
    mPhases4[numHarmonicsV4] -= simd::floor(mPhases4[numHarmonicsV4]);
}

但:

  1. 我想我可以更多地优化它,也许用一些数学技巧,或者以一些增量保存
  2. 我不喜欢重复“相同的代码”一次V4,一次remainder(如果谐波数不是 % 4):有没有办法在最后的 V4 放置中放置一种“掩码”(例如)幅度为 0?(所以它在同一个块中执行相同的操作,但不会汇总到最终输出)。

标签: c++optimizationvectorizationsimdsse2

解决方案


问题的第二部分是最简单的。幅度为 0 的任何谐波都不会影响正弦输出,因此您只需填充mMagnitude为 4 的倍数。

正如 Damien 指出的那样,sin(x)价格昂贵。但由欧拉exp(x)=cos(x) + i sin(x),和exp(x+dx)==exp(x)*exp(dx)。每一步都只是一个复杂的乘法。


推荐阅读