简体   繁体   English

具有max_element和迭代器的C ++函数=慢3倍

[英]c++ function with max_element & iterator = 3x slower

The program I am developing gets three times slower when I call the following function. 当我调用以下函数时,我正在开发的程序变慢了三倍。 It wouldn't be bad if it was not called a couple million of times. 如果没有被数百万次调用,那也不错。

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 takes the value 500. Is there another way to speed up significantly this function? periodos的值为500。是否有另一种方法可以大大加快此功能的速度?

Luis 路易斯

EDIT: didn't notice your use of a predicate (the spanish threw me off a bit!) Let me rewrite for a few minutes... 编辑:没有注意到您对谓词的使用(西班牙语使我有点失望!)让我重写几分钟...

max_element and min_element are both iterating through the range, when the entire step could be done in one function. 当整个步骤可以在一个函数中完成时, max_elementmin_element都在范围内进行迭代。

I believe some compilers have a minmax_element function in their STL, but I do not believe it is in the standard. 我相信某些编译器的STL中具有minmax_element函数,但我认为它不在标准中。 You could write your own. 你可以自己写。 I originally wrote this as an untemplated version, but if you have a good compiler it should make no difference. 我最初将其写为非模板版本,但是如果您有一个好的编译器,它应该没有任何区别。

Try something like this (untested) 尝试这样的事情(未经测试)

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>());
}

Contrary to what others say, I don't believe replacing the two calls to std::max_element() and std::min_element() with a single minmax_element() would improve performance in a significant manner, because iterating 2*n times with 1 operation or iterating n times with 2 operations makes little to no difference. 与其他人说的相反,我不认为用单个minmax_element()替换对std::max_element()std::min_element()的两个调用会显着改善性能,因为使用2 * n次迭代1次操作或2次操作n次迭代几乎没有区别。

What would make a difference however is to eliminate the two calls altogether from your algorithm. 然而,将会有所不同的是从您的算法中完全消除了这两个调用。 That is, find the minimum and maximum elements and then check against those when new data comes in, rather than comparing new data against the entire container again. 也就是说,找到最小和最大元素,然后在输入新数据时进行检查,而不是再次将新数据与整个容器进行比较。

 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(...);
    }
}

您可以使用单个std::minmax_element()替换这两个调用。

"3 times slower" with respect to what - to another implementation, or to just not calling this function? 关于什么-另一个实现,还是不调用此函数,“慢3倍”? In the second case it is possible that it is just algorithmic complexity that makes it slower. 在第二种情况下,可能只是算法复杂性使其变慢了。

You didn't explain how your code is used exactly, in some cases you could cache the calculation of the min/max instead of doing that in a loop. 您没有解释代码的确切使用方式,在某些情况下,您可以缓存最小值/最大值的计算,而不是循环进行。 For example, if the input vector is rarely changed, it doesn't make sense to recalculate that every time. 例如,如果输入向量很少更改,则每次重新计算都没有意义。 And even when it changes, you can update min/max without going over periodos elements (dynamic programming might help). 而且即使更改,您也可以更新最小/最大而不需要使用periodos元素(动态编程可能会有所帮助)。

You could also check the generated assembly to check for strange function calls (eg iterators secure checks), I know that at least MSVC 2005/2008 has them enabled by default even in Release mode (see the _SCL_SECURE macro). 您还可以检查生成的程序集以检查奇怪的函数调用(例如,迭代器安全检查),我知道至少MSVC 2005/2008甚至在发布模式下也默认启用了它们(请参见_SCL_SECURE宏)。

This isn't an answer to the specific question about performance, so maybe it has no value. 这不是有关性能的特定问题的答案,因此也许没有任何价值。 But it seems that the excludeWrong compare function would cause unexpected or possibly implementation-dependent results. 但是似乎excludeWrong比较函数会导致意外或可能与实现相关的结果。 If the first value compared is -1 , then it may be computed as both the min and the max for all cases. 如果比较的第一个值是-1 ,则可以将所有情况下的最小值和最大值都计算为该值。 I tested with both gcc v4.0.2 and Microsoft's compiler v15.00.21022.08. 我同时使用gcc v4.0.2和Microsoft的编译器v15.00.21022.08进行了测试。 For example, the following: 例如,以下内容:

   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;

prints: 印刷品:

min: -1
max: -1

Maybe that is the desired result, but it seems a bit odd. 也许这是理想的结果,但似乎有些奇怪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM