Этот вопрос, хотя и довольно старый, требует некоторых тестов, поскольку он требует не самого идиоматического способа, или способа, который может быть записан с наименьшим количеством строк, но самым быстрым способом. И глупо отвечать на этот вопрос без реального тестирования. Поэтому я сравнил четыре решения: memset против std :: fill против ZERO ответа AnT и решения, которое я сделал с использованием встроенных функций AVX.
Обратите внимание, что это решение не является универсальным, оно работает только с 32- или 64-битными данными. Прокомментируйте, если этот код делает что-то неправильно.
#include<immintrin.h>
#define intrin_ZERO(a,n){\
size_t x = 0;\
const size_t inc = 32 / sizeof(*(a));/*size of 256 bit register over size of variable*/\
for (;x < n-inc;x+=inc)\
_mm256_storeu_ps((float *)((a)+x),_mm256_setzero_ps());\
if(4 == sizeof(*(a))){\
switch(n-x){\
case 3:\
(a)[x] = 0;x++;\
case 2:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
else if(8 == sizeof(*(a))){\
switch(n-x){\
case 7:\
(a)[x] = 0;x++;\
case 6:\
(a)[x] = 0;x++;\
case 5:\
(a)[x] = 0;x++;\
case 4:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 3:\
(a)[x] = 0;x++;\
case 2:\
((long long *)(a))[x] = 0;break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
}
Я не буду утверждать, что это самый быстрый метод, так как я не специалист по оптимизации низкого уровня. Скорее, это пример правильной архитектурно-зависимой реализации, которая быстрее, чем memset.
Теперь о результатах. Я рассчитал производительность для массивов размера 100 int и long long, как статически, так и динамически распределенных, но за исключением msvc, который устранял мертвый код на статических массивах, результаты были чрезвычайно сопоставимы, поэтому я покажу только производительность динамического массива. Разметка времени составляет миллисекунды для 1 миллиона итераций с использованием функции часов с низкой точностью time.h.
clang 3.8 (Используя интерфейс clang-cl, флаги оптимизации = / OX / arch: AVX / Oi / Ot)
int:
memset: 99
fill: 97
ZERO: 98
intrin_ZERO: 90
long long:
memset: 285
fill: 286
ZERO: 285
intrin_ZERO: 188
gcc 5.1.0 (флаги оптимизации: -O3 -march = native -mtune = native -mavx):
int:
memset: 268
fill: 268
ZERO: 268
intrin_ZERO: 91
long long:
memset: 402
fill: 399
ZERO: 400
intrin_ZERO: 185
msvc 2015 (флаги оптимизации: / OX / arch: AVX / Oi / Ot):
int
memset: 196
fill: 613
ZERO: 221
intrin_ZERO: 95
long long:
memset: 273
fill: 559
ZERO: 376
intrin_ZERO: 188
Здесь происходит много интересного: llvm убивает gcc, типичные точечные оптимизации MSVC (он производит впечатляющее устранение мертвого кода на статических массивах, а затем имеет ужасную производительность для заполнения). Хотя моя реализация значительно быстрее, это может быть только потому, что она признает, что очистка битов имеет гораздо меньше накладных расходов, чем любая другая операция настройки.
Реализация Clang заслуживает большего внимания, так как она значительно быстрее. Некоторое дополнительное тестирование показывает, что его memset на самом деле специализирован для нулевых - ненулевых memset для 400-байтового массива намного медленнее (~ 220 мс) и сопоставим с gcc. Однако ненулевое значение memset с 800-байтовым массивом не влияет на скорость, вероятно, поэтому в этом случае их memset имеет худшую производительность, чем моя реализация - специализация предназначена только для небольших массивов, а отсечение составляет около 800 байтов. Также обратите внимание, что gcc 'fill' и 'ZERO' не оптимизируются для memset (глядя на сгенерированный код), gcc просто генерирует код с идентичными характеристиками производительности.
Вывод: memset на самом деле не оптимизирован для этой задачи, как люди могли бы это представить (иначе gcc, msvc и llvm memset имели бы одинаковую производительность). Если производительность имеет значение, то memset не должен быть окончательным решением, особенно для этих неудобных массивов среднего размера, потому что он не специализируется на очистке битов и не оптимизирован вручную лучше, чем компилятор может сделать сам по себе.
new
это C ++ ...