具有Max元素和迭代器= 3X的C++函数

具有Max元素和迭代器= 3X的C++函数,c++,algorithm,const-iterator,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() <

当我调用下面的函数时,我正在开发的程序会慢三倍。 如果它没有被呼叫几百万次,那也不坏

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。 是否有其他方法显著加快此功能


Luis

你可以用一个std::minmax_元素替换这两个调用。

你可以用一个std::minmax_元素替换这两个调用。

编辑:没有注意到你使用了谓词,西班牙语让我有点不舒服!让我重写几分钟

当整个步骤可以在一个函数中完成时,max_元素和min_元素都在该范围内迭代

我相信有些编译器的STL中有一个minmax_元素函数,但我不相信标准中有。你可以自己写。我最初写这篇文章是作为一个未模板的版本,但是如果你有一个好的编译器,它应该不会有什么不同

试试这种未经测试的东西

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_元素和min_元素都在该范围内迭代

我相信有些编译器的STL中有一个minmax_元素函数,但我不相信标准中有。你可以自己写。我最初写这篇文章是作为一个未模板的版本,但是如果你有一个好的编译器,它应该不会有什么不同

试试这种未经测试的东西

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

与其他人所说的相反,我认为用一个minmax_元素替换对std::max_元素和std::min_元素的两个调用不会显著提高性能,因为用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(...);
    }
}

与其他人所说的相反,我认为用一个minmax_元素替换对std::max_元素和std::min_元素的两个调用不会显著提高性能,因为用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(...);
    }
}

3倍于其他实现,或者只是不调用此函数?在第二种情况下,可能正是算法的复杂性使其速度变慢

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


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

3倍于其他实现的速度,或者只是不调用此函数?在第二种情况下,可能正是算法的复杂性使其速度变慢

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


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

这不是关于性能的特定问题的答案,因此可能没有任何价值。但是,ExcludeError比较函数似乎会导致意外的或可能依赖于实现的结果。如果比较的第一个值为-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;

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

这并不是关于性能的具体问题的答案,所以可能它没有价值。但是,exclude错误的比较函数似乎会导致unspec ted或可能与实现相关的结果。如果比较的第一个值为-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;


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

您是在调试模式下编译的吗?也许是使用安全的stl样式实现,每次都会对调用进行绑定检查。尝试打开优化。如果不使用min_元素和max_元素,并进行一次迭代以找到这两个元素,可能会更好。顺便说一句,将double与-1进行严格相等比较不是一个好主意。@Jeff Foster:更糟糕的是,在MSVC 2005/2008中,默认情况下在发布模式下也会启用它,必须使用_SCL\u SECURE宏才能禁用它。@sharptooth:为什么-1在所有常见的浮点表示中都是精确的。比较任何浮点结果是否相等是一个坏主意,但这看起来像一个幻数,而不是一个计算。您是在调试模式下编译的吗?也许是使用安全的stl样式实现,每次都会对调用进行绑定检查。尝试打开优化。如果不使用min_元素和max_元素,并进行一次迭代以找到这两个元素,可能会更好。顺便说一句,将double与-1进行严格相等比较不是一个好主意。@Jeff Foster:更糟糕的是,在MSVC 2005/2008中,默认情况下在发布模式下也会启用它,必须使用_SCL\u SECURE宏才能禁用它。@sharptooth:为什么-1在所有常见的浮点表示中都是精确的。比较任何浮点结果是否相等是一个坏主意,但这看起来像一个幻数,而不是一个计算。这是一个好的点-有时。我们没有足够的信息,只是这个函数调用了很多。如果他只是获取一个数据流,就没有办法加快算法的速度+1谁说路易斯多次通过同一个向量?他只是说该函数会被多次使用。无论如何,由于缓存未命中,在任何大型集合上迭代两次比一次完成所有工作要昂贵得多。但是,500个元素不是一个大容器。@BenVoigt这没关系。我会更新我的答案,以便更清楚地了解它。@BenVoigt您仍然在谈论一个恒定因素的性能改进,而我建议性能改进的数量级!这是一个很好的观点——有时。我们没有足够的信息,只是这个函数调用了很多。如果他只是获取一个数据流,就没有办法加快算法的速度+1谁说路易斯多次通过同一个向量?他只是说该函数会被多次使用。无论如何,由于缓存未命中,在任何大型集合上迭代两次比一次完成所有工作要昂贵得多。但是,500个元素不是一个大容器。@BenVoigt这没关系。我会更新我的答案,以便更清楚地了解它。@BenVoigt您仍然在谈论一个恒定因素的性能改进,而我建议性能改进的数量级!注意:这可能需要一个带有C++0x库的新编译器。注意:这可能需要一个带有C++0x库的新编译器。std::minmax_元素在C++0x的3225草稿中,所以它将是标准的。@Ben Voigt:它是葡萄牙语,不是西班牙语!谢谢你的回答。我将实现它,尽管我对模板还不太熟悉。在值得称赞的地方给予赞扬。这是rlbond极好的回答,也是对语言的不幸误认。你是对的Ben Voigt。之前的评论是针对邦德的!很抱歉。std::minmax_元素在C++0x的3225草稿中,所以它将是标准的。@Ben Voigt:它是葡萄牙语,不是西班牙语!谢谢你的回答。我将实现它,尽管我对模板还不太熟悉。在值得称赞的地方给予赞扬。这是rlbond极好的回答,也是对语言的不幸误认。你是对的Ben Voigt。之前的评论是针对邦德的!对不起,我应该说清楚的,对不起。它的速度是未调用此函数时的3倍。每次调用函数时都必须更改输入向量。我用的是g++。对不起,我应该说得更清楚。它的速度是未调用此函数时的3倍。每次调用函数时都必须更改输入向量。我使用的是g++。感谢您指出这一点,即使这与问题没有直接关系。excludeError作为比较函数给出,如果第一个参数被认为小于第二个参数,则该函数应返回true,否则返回false。因此,返回false并不是过滤掉一个值的方法——相反,它会弄乱比较结果……感谢您指出这一点,即使它与问题没有直接关系。excludeError作为比较函数给出,如果第一个参数小于第二个参数,则该函数将返回true 论点,否则为假。因此,返回false并不是过滤掉一个值的方法——它反而会弄乱比较。。。