【问题标题】:Optimizing this 'statistical coincidence' finding algorithm优化这种“统计巧合”查找算法
【发布时间】:2021-02-25 02:47:24
【问题描述】:

目标

以下代码旨在从高斯分布中获取vector<vector<float> > 的随机数,并执行以下操作:

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

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

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

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

我如何做到这一点:

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

我继续迭代。如果我到达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));
            }

        }


    }

}

【问题讨论】:

    标签: c++ algorithm statistics gaussian


    【解决方案1】:

    你可以立即在你的内部循环中做的一件事。我知道 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 转换为 double 然后再转换回 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::reserve()和set::reserve()。

    您是否向我们提供了整个算法?容器索引的内容不会在任何地方使用。

    请告诉我您通过这些更改获得了多少时间。

    【讨论】:

    • @MohsanAli 复杂性是 NumRows x NumCols。如果您必须检查所有行和列,则不能低于此值。这些更改可能会获得 30% 到 40% 的性能提升。除法非常慢。
    • 我不知道。
    猜你喜欢
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 2019-10-25
    相关资源
    最近更新 更多