【发布时间】:2021-01-17 21:08:19
【问题描述】:
我正在使用矢量化(仅 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]);
}
但是:
- 我认为我可以对其进行更多优化,也许可以通过一些数学技巧,或者以一些增量进行保存
- 我不喜欢为
V4重复一次“相同的代码”,为remainder重复一次(如果谐波数不是 % 4):有没有办法放置一种“掩码”到最后一个 V4 将(例如)幅度设置为 0? (因此它在同一个块中执行相同的操作,但不会对最终输出求和)。
【问题讨论】:
-
水平求和到
outputinside 循环的成本很高。取而代之的是,在最后累积成一个和向量和 hsum 一次。 Fastest way to do horizontal SSE vector sum (or other reduction) -
计算以
sin计算为主。有一些技巧可以迭代计算正弦 (sin(a+b) = ...),而无需调用sin函数。在这种情况下,你要注意舍入误差的累积,不时重新计算准确的正弦值。 -
另外,
sin与您的其他代码相比非常昂贵,具体取决于您选择的精度与性能权衡(或您选择的库)。 (虽然floor在没有 SSE4.1 的情况下是不平凡的;处理可能大量数字的通用版本可能很昂贵:Calculating floor & ceil of vector2 double using pre-SSE4。如果您不需要处理大量数字,请使用加/减来滚动您自己的地板大常数可以舍入,尽管 IIRC 这个技巧只直接给你当前的舍入模式(到最近,而不是朝向 -Inf) -
如果你有一个恒定的相位增量dphi,那么
sin((n+1)dphi) = sin(n dphi) cos(dphi) + cos(n dphi) sin(dphi)。cos(n+1)dphi也一样。您只计算一次cos(dphi)和sin(dphi)...。如果原点有相位,则迭代公式仍然有效。我已经为多普勒生成使用了数十亿次这个技巧 -
再次查看 Msalters 的回答。不需要直接调用
exp(i*),而是实现迭代公式,用一个简单的复数乘法就可以了
标签: c++ optimization vectorization simd sse2