Подтвердить что ты не робот

Является ли "==" в отсортированном массиве не быстрее, чем несортированный массив?

Примечание: предполагаемый дублирующий вопрос, я думаю, в основном связан с "<" и " > " сравнение, но не сравнение "==" и, следовательно, не отвечает на мой вопрос об эффективности оператора "==" .

Долгое время я считал, что "обработка" отсортированного массива должна быть быстрее, чем несортированный массив. Сначала я подумал, что использование "==" в отсортированном массиве должно быть быстрее, чем в несортированном массиве, потому что, я думаю, о том, как работает предсказание ветвей:

UNSORTEDARRAY:

5 == 100 F
43 == 100 F
100 == 100 T
250 == 100 F
6 == 100 F
(other elements to check)

SORTEDARRAY:

5 == 100 F
6 == 100 F
43 == 100 F
100 == 100 T
(no need to check other elements, so all are F)

поэтому я предполагаю, что SORTEDARRAY должен быть быстрее, чем UNSORTEDARRAY, но сегодня я использовал код для генерации 2 массивов в заголовке для тестирования, и предсказание ветвления казалось не сработало, как я думал.

Я создал несортированный массив и отсортированный массив для проверки:

srand(time(NULL));
int UNSORTEDARRAY[524288];
int SORTEDARRAY[sizeof(UNSORTEDARRAY)/sizeof(int)];
for(int i=0;i<sizeof(SORTEDARRAY)/sizeof(int);i++){
    SORTEDARRAY[i]=UNSORTEDARRAY[i]=rand();
}
sort(SORTEDARRAY,SORTEDARRAY+sizeof(SORTEDARRAY)/sizeof(int));
string u="const int UNSORTEDARRAY[]={";
string s="const int SORTEDARRAY[]={";
for(int i=0;i<sizeof(UNSORTEDARRAY)/sizeof(int);i++){
    u+=to_string(UNSORTEDARRAY[i])+",";
    s+=to_string(SORTEDARRAY[i])+",";
}
u.erase(u.end()-1);
s.erase(s.end()-1);
u+="};\n";
s+="};\n";
ofstream out("number.h");
string code=u+s;
out << code;
out.close();

чтобы проверить, просто подсчитайте, равно ли value == RAND_MAX/2 следующим образом:

#include "number.h"
int main(){
int count;
    clock_t start = clock();
    for(int i=0;i<sizeof(SORTEDARRAY)/sizeof(int);i++){
        if(SORTEDARRAY[i]==RAND_MAX/2){
            count++;
        }
    }
    printf("%f\n",(float)(clock()-start)/CLOCKS_PER_SEC);
}

выполните три раза:

UNSORTEDARRAY

0.005376
0.005239
0.005220

SORTEDARRAY

0.005334
0.005120
0.005223

кажется небольшая разница в производительности, поэтому я не поверила, а затем попыталась изменить "SORTEDARRAY [i] == RAND_MAX/2" на "SORTEDARRAY [i] > RAND_MAX/2", чтобы увидеть, разница:

UNSORTEDARRAY

0.008407
0.008363
0.008606

SORTEDARRAY

0.005306
0.005227
0.005146

на этот раз есть большая разница.

Является ли "==" в отсортированном массиве не быстрее, чем несортированный массив? Если да, то почему " > " в ​​отсортированном массиве выполняется быстрее, чем несортированный массив, но "==" не является?

4b9b3361

Ответ 1

Одна вещь, которая сразу приходит в голову, - это алгоритм прогнозирования ветвления процессора.

В случае сравнения > в отсортированном массиве поведение ветвления очень непротиворечиво: во-первых, условие if постоянно ложно, то оно последовательно верно. Это очень хорошо сочетается с простейшим предсказанием ветвей.

В несортированном массиве результат условия > является, по существу, случайным, что предотвращает любое предсказание ветвления.

Это ускоряет сортировку.

В случае сравнения == в большинстве случаев условие ложно и только очень редко оно истинно. Это хорошо работает с предсказанием ветвей независимо от того, отсортирован ли массив или нет. Временные значения по существу одинаковы.

Ответ 2

N.B. Я принимаю этот ответ, потому что он слишком длинный для комментария.

Эффект здесь - это то, что уже подробно объяснено в подробных ответах на этот вопрос. Обработка отсортированного массива в этом случае была быстрее из-за предсказания ветвления.

Здесь преступник снова является прогнозом ветвления. Тест == очень редко выполняется, поэтому предсказание ветвлений работает примерно одинаково для обоих. Когда вы изменили его на >, вы получили объяснение по этому вопросу и по той же причине.


Мораль:

Я считаю, что "обработка" отсортированного массива должна быть быстрее, чем [an] несортированный массив.

Вам нужно знать, почему. Это не какое-то магическое правило, и это не всегда так.

Ответ 3

Сравнение == имеет меньшее отношение к порядку, чем >. Правильное или неправильное прогнозирование == будет зависеть только от количества повторяющихся значений и их распределения.

Вы можете использовать perf stat для просмотра счетчиков производительности...

[email protected] /tmp $ lz4 -d ints | perf stat ./proc-eq >/dev/null
Successfully decoded 104824717 bytes

 Performance counter stats for './proc-eq':

       5226.932577      task-clock (msec)         #    0.953 CPUs utilized
                31      context-switches          #    0.006 K/sec
                24      cpu-migrations            #    0.005 K/sec
             3,479      page-faults               #    0.666 K/sec
    15,763,486,767      cycles                    #    3.016 GHz
     4,238,973,549      stalled-cycles-frontend   #   26.89% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,522,072,416      instructions              #    2.00  insns per cycle
                                                  #    0.13  stalled cycles per insn
     8,515,545,178      branches                  # 1629.167 M/sec
        10,261,743      branch-misses             #    0.12% of all branches

       5.483071045 seconds time elapsed

[email protected] /tmp $ lz4 -d ints | sort -n | perf stat ./proc-eq >/dev/null
Successfully decoded 104824717 bytes

 Performance counter stats for './proc-eq':

       5536.031410      task-clock (msec)         #    0.348 CPUs utilized
               198      context-switches          #    0.036 K/sec
                21      cpu-migrations            #    0.004 K/sec
             3,604      page-faults               #    0.651 K/sec
    16,870,541,124      cycles                    #    3.047 GHz
     5,300,218,855      stalled-cycles-frontend   #   31.42% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,526,006,118      instructions              #    1.87  insns per cycle
                                                  #    0.17  stalled cycles per insn
     8,516,336,829      branches                  # 1538.347 M/sec
        10,980,571      branch-misses             #    0.13% of all branches

[email protected] /tmp $ lz4 -d ints | perf stat ./proc-gt >/dev/null
Successfully decoded 104824717 bytes

 Performance counter stats for './proc-gt':

       5293.065703      task-clock (msec)         #    0.957 CPUs utilized
                38      context-switches          #    0.007 K/sec
                50      cpu-migrations            #    0.009 K/sec
             3,466      page-faults               #    0.655 K/sec
    15,972,451,322      cycles                    #    3.018 GHz
     4,350,726,606      stalled-cycles-frontend   #   27.24% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,537,365,299      instructions              #    1.97  insns per cycle
                                                  #    0.14  stalled cycles per insn
     8,515,606,640      branches                  # 1608.823 M/sec
        15,241,198      branch-misses             #    0.18% of all branches

       5.532285374 seconds time elapsed

[email protected] /tmp $ lz4 -d ints | sort -n | perf stat ./proc-gt >/dev/null

      15.930144154 seconds time elapsed

 Performance counter stats for './proc-gt':

       5203.873321      task-clock (msec)         #    0.339 CPUs utilized
                 7      context-switches          #    0.001 K/sec
                22      cpu-migrations            #    0.004 K/sec
             3,459      page-faults               #    0.665 K/sec
    15,830,273,846      cycles                    #    3.042 GHz
     4,456,369,958      stalled-cycles-frontend   #   28.15% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,540,409,224      instructions              #    1.99  insns per cycle
                                                  #    0.14  stalled cycles per insn
     8,516,186,042      branches                  # 1636.509 M/sec
        10,205,058      branch-misses             #    0.12% of all branches

      15.365528326 seconds time elapsed