优化此'statistical coincidence'查找算法



目标

下面的代码被设计为从高斯分布中获取随机数的vector<vector<float> >,并执行以下操作:

  1. 在向量的所有n列中同时迭代,直到遇到第一个超过某个阈值的值。

  2. 继续迭代,直到a(遇到超过该阈值的第二个值,使得该值来自与第一个找到的值不同的列,或者b(超过某个最大迭代次数。

  3. 在a(的情况下,继续迭代,直到c(您发现第三个值超过阈值,使得该值来自与第一个发现值第二个发现值不同的列,或者b(您超过了第一个发现值的最大迭代次数。在b(的情况下,重新开始,除了这次在第一个找到的值之后的一行开始迭代。

  4. 在c(的情况下,将一添加到计数器,并向前跳转一些x行。在d(的情况下,从头开始,除了这次在第一个找到的值之后的一行开始迭代。

我如何做到这一点:

在我看来,最具挑战性的部分是确保所有三个值都由一个独特的专栏贡献。为了解决这个问题,我使用了std::set。我遍历vector<vector<float> >的每一行,然后遍历该行的每一列。我检查每一列是否有超过阈值的值,并将其列数存储在std::集中。

我继续迭代。如果我达到max_iterations,我会跳回到第一个找到的值之后的一,清空集合,然后重置计数器。如果std::set的大小为3,我会在计数器上加一。

我的问题:

此代码需要在大小为数十列、数十万到数百万行的多维向量上运行。到目前为止,速度非常慢。如果可能的话,我想大幅提高绩效。

我的代码:

void findRate(float thresholdVolts){
set<size_t> cache;
vector<size_t> index;
size_t count = 0, found = 0;
for(auto rowItr = waveform.begin(); rowItr != waveform.end(); ++rowItr){
auto &row = *rowItr;
for(auto colnItr = row.begin(); colnItr != row.end(); ++colnItr){
auto &cell = *colnItr;
if(abs(cell/rmsVoltage) >= (thresholdVolts/rmsVoltage)){
cache.insert(std::distance(row.begin(), colnItr));
index.push_back(std::distance(row.begin(), colnItr));
}
}
if(cache.size() == 0) count == 0;
if(cache.size() == 3){
++found;
cache.clear();
if(std::distance(rowItr, output.end()) > ((4000 - count) + 4E+6)){
std::advance(rowItr, ((4000 - count) + 4E+6));
}
}

}
}

有一件事你可以马上做,在你的内部循环中。我知道rmsVoltage是一个外部变量,在函数执行过程中是恒定的。

for(auto colnItr = row.begin(); colnItr != row.end(); ++colnItr){
auto &cell = *colnItr;

// you can remove 2 divisions here.  Divisions are the slowest
// arithmetic instructions on any cpu
//
//  this: 
//    if(abs(cell/rmsVoltage) >= (thresholdVolts/rmsVoltage)){
//
// becomes this
if (abs(cell) >= thresholdVolts) {
cache.insert(std::distance(row.begin(), colnItr));
index.push_back(std::distance(row.begin(), colnItr));
}

下面是:为什么要在size_t中添加一个浮点常量??这可能会导致不必要的size_t转换为两倍,然后再转换回size_t,一些编译器可能会处理这一问题,但绝对不是全部。

这些操作成本相对较高。

// this:
//  if(std::distance(rowItr, output.end()) > ((4000 - count) + 4E+6)){
//    std::advance(rowItr, ((4000 - count) + 4E+6));
//  }
if (std::distance(rowItr, output.end()) > (4'004'000 - count))
std::advance(rowItr, 4'004'000 - count);

此外,在观察到函数在内存中的需求后,应该使用vector<gt;:reserve((,并设置<gt;:reserve((。

你给我们完整的算法了吗?容器索引的内容不会在任何地方使用。

请告诉我你从这些变化中获得了多少时间。

最新更新