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

发布于 2024-10-19 07:50:37 字数 722 浏览 4 评论 0原文

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

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。 还有其他方法可以显着加快此功能吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

-小熊_ 2024-10-26 07:50:37

当整个步骤可以在一个函数中完成时,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>());
}

max_element and min_element are both iterating through the range, when the entire step could be done in one function.

I believe some compilers have a minmax_element function in their STL, but I do not believe it is in the standard. 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>());
}
七秒鱼° 2024-10-26 07:50:37

与其他人所说的相反,我不相信用单个 minmax_element 替换对 std::max_element()std::min_element() 的两个调用() 会显着提高性能,因为使用 1 个操作迭代 2*n 次或使用 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(...);
    }
}

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.

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(...);
    }
}
莫言歌 2024-10-26 07:50:37

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

You could replace those two calls with a single std::minmax_element().

梦忆晨望 2024-10-26 07:50:37

“慢 3 倍”相对于什么 - 另一个实现,或者只是不调用这个函数?在第二种情况下,可能只是算法复杂性导致速度变慢。

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

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

"3 times slower" with respect to what - to another implementation, or to just not calling this function? 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).

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).

难如初 2024-10-26 07:50:37

这不是有关性能的具体问题的答案,因此也许它没有价值。但似乎 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;

prints:

min: -1
max: -1

也许这就是期望的结果,但看起来有点奇怪。

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. If the first value compared is -1, then it may be computed as both the min and the max for all cases. I tested with both gcc v4.0.2 and Microsoft's compiler 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文