带有max_element&的c ++函数迭代器=慢3倍

时间:2011-02-24 15:05:02

标签: c++ algorithm const-iterator

当我调用以下函数时,我正在开发的程序变慢了三倍。 如果没有被称为几百万次也不会坏。

double obterNormLarguraBanda(const std::vector<double>& v, int periodos)
{
    int aa; 
    double maximo, minimo, valor;
    std::vector<double>::const_iterator inicio;
    if (v.size() < periodos)
    {   
        inicio = v.begin();
    }   
    else
    {   
        inicio = v.end() - periodos;
    }   
    maximo = *max_element(inicio, v.end(), excludeWrong);
    minimo = *min_element(inicio, v.end(), excludeWrong);
    return (v.back()-minimo)/(maximo - minimo);
}

bool excludeWrong(double i, double j)
{
    if (i==-1 || j==-1) return false;
    return i<j;
}

periodos取值500。 还有另一种方法可以显着加快这个功能吗?

路易斯

5 个答案:

答案 0 :(得分:3)

编辑:没注意到你对谓词的使用(西班牙语让我失望了!)让我重写几分钟......

当整个步骤可以在一个函数中完成时,

max_elementmin_element都在遍历范围。

我相信一些编译器在他们的STL中有minmax_element函数,但我不相信它在标准中。你可以写自己的。我最初把它写成一个没有模板的版本,但如果你有一个好的编译器,它应该没有区别。

尝试这样的事情(未经测试)

template <typename Iter, typename Pred>
void minmax_element(Iter begin, Iter end, Iter& min, Iter& max, const Pred& comp)
{
    min = begin;
    max = begin;

    typedef std::iterator_traits<Iter>::value_type T;
    for (++begin; begin != end; ++begin)
    {
        if (comp(*max, *begin))
            max = begin;
        else if (comp(*begin, *min))
            min = begin;
    }
}

template <typename Iter>
void minmax_element(Iter begin, Iter end, Iter& min, Iter& max)
{
    minmax_element(begin, end, min, max, std::less<std::iterator_traits<Iter>::value_type>());
}

答案 1 :(得分:3)

与其他人所说的相反,我认为用std::max_element()取代对std::min_element()minmax_element()的两次调用会以显着的方式改善性能,因为迭代2 * n次操作1次或用2次操作迭代n次几乎没有差别。

然而,有什么不同之处在于从算法中完全消除两个调用。也就是说,找到最小和最大元素,然后在新数据进入时检查它们,而不是再次将新数据与整个容器进行比较。

 double obterNormLarguraBanda(const std::vector<double>& v,
                              double maximo, double minimo)
{
    return (v.back()-minimo)/(maximo - minimo);
}

bool excludeWrong(double i, double j)
{
    if (i==-1 || j==-1) return false;
    return i<j;
}

// usage example
void f()
{
    std::vector<double> v;
    // ...
    double maximo = *max_element(inicio, v.end(), excludeWrong);
    double minimo = *min_element(inicio, v.end(), excludeWrong);
    for( int i = 0; i != 1000; ++i ) {
        // if( ! excludeWrong(new_datum, maximo) ) maximo = new_datum;
        // if( excludeWrong(new_datum, minimo) ) minimo = new_datum;
        double d = obterNormLarguraBanda(...);
    }
}

答案 2 :(得分:1)

您可以用一个std::minmax_element()替换这两个电话。

答案 3 :(得分:0)

对于另一个实现,或者只是不调用此函数,<3>“慢3倍”?在第二种情况下,它可能只是算法的复杂性使它变慢。

您没有解释您的代码是如何使用的,在某些情况下,您可以缓存min / max的计算,而不是在循环中执行此操作。例如,如果很少更改输入向量,则每次重新计算都没有意义。即使它发生变化,您也可以在不超过periodos元素的情况下更新最小值/最大值(动态编程可能有所帮助)。

您还可以检查生成的程序集以检查奇怪的函数调用(例如迭代器安全检查),我知道至少MSVC 2005/2008默认情况下启用它们,即使在发布模式下也是如此(参见_SCL_SECURE宏)。

答案 4 :(得分:0)

这不是关于性能的具体问题的答案,所以也许没有价值。但似乎excludeWrong比较函数会导致意外或可能依赖于实现的结果。如果比较的第一个值是-1,则可以将其计算为所有情况的最小值和最大值。我使用gcc v4.0.2和Microsoft的编译器v15.00.21022.08进行了测试。例如,以下内容:

   std::vector<double> v;
   v.push_back( -1 );
   v.push_back( 1 );
   v.push_back( 2 );
   cout << "min: " << *min_element( v.begin(), v.end(), excludeWrong ) << endl;
   cout << "max: " << *max_element( v.begin(), v.end(), excludeWrong ) << endl;

打印:

min: -1
max: -1

也许这是理想的结果,但似乎有点奇怪。