-1

次の 7 つの関数をテストしましたが、なぜ結合 7 が結合 5 よりも優れているのか理解できません。「()」の位置が違うだけなので。

誰でも私に説明できますか?

これが私のコードです:

#include "Common.h"

#define PLUS
#ifdef PLUS
#define INDENT 0
#define OP +
#else
#define INDENT 1
#define OP *
#endif
typedef int data_t;
typedef struct
{
    long int len;
    data_t *data;
}vec_rec, *vec_ptr;
vec_ptr new_vec(long int len)
{
    vec_ptr result = (vec_ptr)malloc(sizeof(vec_rec));  //Allocate header structure
    if(!result) return NULL;
    result->len = len;
    if(len > 0)     //Allocate array
    {
        data_t* data = (data_t*)calloc(len, sizeof(data_t));
        if(!data)
        {
            free((void*)result);
            return NULL;
        }
        result->data = data;
    }
    else result->data = NULL;
    return result;
}
int get_vec_element(vec_ptr v, long int index, data_t * dest)
{
    if(index < 0 || index >= v->len) return 0;
    *dest = v->data[index];
    return 1;
}
long int vec_length(vec_ptr v)
{
    return v->len;
}
data_t* get_vec_start(vec_ptr v)
{
    return v->data;
}

void combine5(vec_ptr v, data_t* dest)  
{
    long int i;
    long int length = vec_length(v);
    long int limit = length - 1;
    data_t* data = get_vec_start(v);
    data_t acc = INDENT;

    for(i = 0; i < limit; i += 2)
    {
        acc = (acc OP data[i]) OP data[i + 1];  
    }
    for(; i < length; i++)
        acc = acc OP data[i];
    *dest = acc;
}

void combine7(vec_ptr v, data_t* dest)
{
    long int i;
    long int length = vec_length(v);
    long int limit = length - 1;
    data_t* data = get_vec_start(v);
    data_t acc = INDENT;

    for(i = 0; i < limit; i += 2)
    {
        acc = acc OP (data[i] OP data[i + 1]);
    }
    for(; i < length; i++)
        acc = acc OP data[i];
    *dest = acc;
}

std::mt19937 gen;
int roll_die() {

    std::uniform_int_distribution<> dist(1, 6);

    return dist(gen);

}

int main()
{
    const size_t len = 10000000;
    auto vec_pointer = new_vec(len);

    std::generate(vec_pointer->data, vec_pointer->data + vec_pointer->len, roll_die);
    std::cout << "Initialized datas..." << std::endl;
    /*std::copy(vec_pointer->data, vec_pointer->data + vec_pointer->len, 
        std::ostream_iterator<int>(std::cout, "\t"));*/

    data_t dest = 0;

    utility::CStopwatch stopwatch5;
    combine5(vec_pointer, &dest);
    std::cout << "combine5 elapsed time(microseconds): " << stopwatch5.NowInMicro() << std::endl;

    utility::CStopwatch stopwatch7;
    combine7(vec_pointer, &dest);
    std::cout << "combine7 elapsed time(microseconds): " << stopwatch7.NowInMicro() << std::endl;
}

そして、ここに私の結果があります:

Initialized datas...
combine5 elapsed time(microseconds): 16934
combine7 elapsed time(microseconds): 14858
4

3 に答える 3

1

acc = (acc OP data[i]) OP data[i + 1]; よりも自然に遅い
acc = acc OP (data[i] OP data[i + 1]);

最初のケースでは、異なる操作でデータ要素 data[i] と data[i+1] にアクセスしようとするため、かなりのオーバーヘッドが発生しますが、2 番目のケースでは、次の操作と同時にそれらにアクセスしようとします。 (data[i] OP data[i + 1])それらは隣接するメモリ位置であり、相互に反復する方が、別々の瞬間にアクセスするよりも比較的高速であるためです。

于 2013-04-22T15:52:44.120 に答える
0

さまざまな関数のパフォーマンスが異なる理由を知りたい場合は、コンパイラによって生成されたアセンブリ コードを分析することをお勧めします。関数は十分に単純であり、通常これに慣れていない人でもアセンブリで読むことができます。

関数 3では、各反復で逆参照します。

for(i = 0; i < length; i ++)
{
    *dest = *dest OP data[i];   
}

関数 4では、最後にのみ逆参照します。

for(i = 0; i < length; i ++)
{
    acc = acc OP data[i];
}
*dest = acc;

関数 5は、反復回数の半分しか反復しないため高速です。参照:ループの巻き戻し

于 2013-04-22T15:22:35.230 に答える
0

なぜこれらが大きく異なるべきなのかは明確ではありません (確かに fatih_k による説明は私を納得させません)。演算子は可換であるため、コンパイラはとにかく順序を変更したい場合があります(コンパイラフラグによって異なります)。さまざまなコンパイラ フラグ (特に最適化フラグ) とさまざまなコンパイラ (clang、gcc、icpc) を試しましたか?

また、ループ本体の次の形式はどのように処理されますか?

 {
    acc *= data[i];
    acc *= data[i+1];
 }

補足: くだらないマクロは避けてください。代わりに、テンプレート化されたコードを記述してください。

于 2013-04-22T16:25:39.140 に答える