Geschwindigkeit von STL numerics



  • Hallo,
    ich habe zwei Funktionen verglichen, die mir den Korrelationskoeffizienten zweier Zahlenlisten berechnen. Die eine benutzt STL-Funktionen, die andere berechnet die benoetigten Summen "von Hand". Bei einer Listenlaenge von je 1000000 double's:x
    benoetigt die STL-Version 130000 clock ticks waehrend die "von Hand" Version nur 70000 benoetigt (kompiliert mit g++ -O2 -march=k6 test.cpp).

    Kann mir jemand erklaeren, woran das liegt? Ich haette erwartet, dass die STL vergleichbar, wenn nicht gar schneller waere. Hier der Code:

    #include <iostream>
    #include <numeric>
    #include <cmath>
    #include <vector>
    #include <time.h>
    
    // compare two versions of calculating correlation coefficients
    // using STL functions
    template <typename T> T CC_stl(const std::vector<T>& l1,
                                   const std::vector<T>& l2)
    {
        T corr_coefficient;
        T sum1, sum1_sq, sum2, sum2_sq, sum12;
        T nominator;
        T denominator;
    
        int list_size = l1.size();
    
        sum1    = std::accumulate(l1.begin(), l1.end(), 0.0);
        sum2    = std::accumulate(l2.begin(), l2.end(), 0.0);
        sum1_sq = std::inner_product(l1.begin(), l1.end(), l1.begin(), 0.0);
        sum2_sq = std::inner_product(l2.begin(), l2.end(), l2.begin(), 0.0);
        sum12   = std::inner_product(l1.begin(), l1.end(), l2.begin(), 0.0);
    
        nominator   = sum12 - sum1*sum2/list_size;
        denominator =   (sum1_sq - sum1*sum1/list_size)
            * (sum2_sq - sum2*sum2/list_size);
        corr_coefficient = nominator / std::sqrt(denominator);
        return corr_coefficient;
    }
    
    // manual calculation
    template <typename T> T CC(const std::vector<T>& l1, const std::vector<T>& l2)
    {
        T corr_coefficient;
        T sum1, sum1_sq, sum2, sum2_sq, sum12;
        T nominator;
        T denominator;
    
        sum1 = sum2 = sum1_sq = sum2_sq = sum12 = 0;
    
        int list_size = l1.size();
    
        for ( int i = 0; i < list_size; i++)
        {
            sum1    += l1[i];
            sum2    += l2[i];
            sum1_sq += l1[i]*l1[i];
            sum2_sq += l2[i]*l2[i];
            sum12   += l1[i]*l2[i];
        }
    
        nominator   = sum12 - 1.0*sum1/list_size * sum2;
        denominator = (sum1_sq - 1.0/list_size * sum1*sum1) *
                      (sum2_sq - 1.0/list_size * sum2*sum2);
    
        corr_coefficient = nominator / std::sqrt(denominator);
        return corr_coefficient;
    }
    
    int main()
    {
        const unsigned int points = 1000000;
        std::vector<double> l1(points), l2(points);
    
        clock_t stl0, stl1, std0, std1;
    
        // populate both vectors with numbers
        for ( int i = 0; i < points; i++)
        {
            l1[i] = std::sqrt(1.0*i);
            l2[i] = 1.0/(i+1);
        }
    
        stl0 = clock();
        double cc_stl = CC_stl(l1, l2);
        stl1 = clock();
    
        std0 = clock();
        double cc_std = CC(l1, l2);
        std1 = clock();
    
        std::cout << " STL Version:    " << cc_stl << " clocks: "
                  << stl1 - stl0 << '\n'
                  << " Normal Version: " << cc_std << " clocks: "
                  << std1 - std0 << '\n';
    
        return 0;
    }
    

    Vielen Dank,

    Tim



  • Bei der handgeschriebenen Variante machst du ja alles in einer Schleife und in der STL müssen ja 5 mal der ganze Vektor durchlaufen werden?!



  • ich hab mal den source genommen und bei mir kompiliert, folgende ergebnisse:

    STL Version: -0.0251371 clocks: 234
    Normal Version: -0.0251371 clocks: 282

    STL Version: -0.0251371 clocks: 250
    Normal Version: -0.0251371 clocks: 266

    STL Version: -0.0251371 clocks: 234
    Normal Version: -0.0251371 clocks: 282

    STL Version: -0.0251371 clocks: 234
    Normal Version: -0.0251371 clocks: 266

    STL Version: -0.0251371 clocks: 234
    Normal Version: -0.0251371 clocks: 282

    STL Version: -0.0251371 clocks: 250
    Normal Version: -0.0251371 clocks: 266

    STL Version: -0.0251371 clocks: 250
    Normal Version: -0.0251371 clocks: 266

    STL Version: -0.0251371 clocks: 234
    Normal Version: -0.0251371 clocks: 282

    STL Version: -0.0251371 clocks: 235
    Normal Version: -0.0251371 clocks: 281

    bei mir ist die "handmade" also bissl langsamer.
    habs einfach mit dem aktuellen dev-cpp und standard compiler-einstellungen kompiliert.


Anmelden zum Antworten