Что быстрее/предпочтительнее: memset или для цикла, чтобы обнулить массив из двух пар?
double d[10];
int length = 10;
memset(d, length * sizeof(double), 0);
//or
for (int i = length; i--;)
d[i] = 0.0;
Ответы
Ответ 1
Обратите внимание, что для memset вам нужно передать количество байтов, а не количество элементов, потому что это старая функция C:
memset(d, 0, sizeof(double)*length);
memset может быть быстрее, поскольку он написан на ассемблере, тогда как std::fill
- это функция шаблона, которая просто выполняет цикл внутри.
Но для безопасности типов и более читаемого кода я бы рекомендовал std::fill()
- это способ выполнения С++ и рассмотрим memset
, если требуется оптимизация производительности в этом месте в код.
Ответ 2
Если вам действительно нужно, вы должны попробовать и измерить. Однако наиболее переносимым способом является std:: fill():
std::fill( array, array + numberOfElements, 0.0 );
Ответ 3
Попробуйте это, хотя бы для охлаждения xD
{
double *to = d;
int n=(length+7)/8;
switch(length%8){
case 0: do{ *to++ = 0.0;
case 7: *to++ = 0.0;
case 6: *to++ = 0.0;
case 5: *to++ = 0.0;
case 4: *to++ = 0.0;
case 3: *to++ = 0.0;
case 2: *to++ = 0.0;
case 1: *to++ = 0.0;
}while(--n>0);
}
}
Ответ 4
memset(d,0,10*sizeof(*d));
скорее всего, будет быстрее. Как они говорят, вы также можете
std::fill_n(d,10,0.);
но это, скорее всего, более красивый способ сделать цикл.
Ответ 5
В дополнение к нескольким ошибкам и упущениям в вашем коде использование memset не переносится. Вы не можете предположить, что double со всеми нулевыми битами равен 0.0. Сначала сделайте правильный код, а затем подумайте об оптимизации.
Ответ 6
Предполагая, что длина цикла является интегральным постоянным выражением, наиболее вероятным результатом является то, что хороший оптимизатор распознает как цикл for, так и memset (0). Результатом будет то, что сгенерированная сборка по существу равна. Возможно, выбор регистров может отличаться или настройка. Но предельные издержки на двойную сумму должны быть одинаковыми.
Ответ 7
calloc(length, sizeof(double))
Согласно IEEE-754, представление битов положительного нуля - это все нулевые биты, и нет ничего плохого в том, чтобы требовать соответствия IEEE-754. (Если вам нужно обнулить массив, чтобы его повторно использовать, выберите одно из указанных выше решений).
Ответ 8
В соответствии с этой статьей Википедии о 64-разрядная плавающая точка IEEE 754-1975 бит-шаблон всех 0 будет действительно правильно инициализировать двойной до 0,0. К сожалению, ваш код memset этого не делает.
Вот код, который вы должны использовать:
memset(d, 0, length * sizeof(double));
Как часть более полного пакета...
{
double *d;
int length = 10;
d = malloc(sizeof(d[0]) * length);
memset(d, 0, length * sizeof(d[0]));
}
Конечно, если вы сбросите проверку ошибок, вы должны делать это с возвращаемым значением malloc. sizeof(d[0])
немного лучше, чем sizeof(double)
, потому что он устойчив к изменениям типа d.
Кроме того, если вы используете calloc(length, sizeof(d[0]))
, он очистит память для вас, и последующий memset больше не понадобится. Я не использовал его в примере, потому что тогда кажется, что на ваш вопрос не будет дан ответ.
Ответ 9
Пример не будет работать, потому что вам нужно выделить память для вашего массива. Вы можете сделать это в стеке или в куче.
Это пример, чтобы сделать это в стеке:
double d[50] = {0.0};
После этого не требуется memset.
Ответ 10
memset (d, 10, 0) ошибочен, так как он всего лишь 10 байтов.
Предположим, std:: fill, поскольку намерение является самым ясным.
Ответ 11
Не забудьте сравнить правильно оптимизированный цикл, если вы действительно заботитесь о производительности.
Некоторый вариант устройства Duff, если массив достаточно длинный, а префикс - я не суффикс i-- (хотя большинство компиляторов, вероятно, исправят это автоматически.).
Хотя я бы поставил вопрос, если это самая ценная вещь для оптимизации. Действительно ли это является узким местом для системы?
Ответ 12
В общем случае memset будет намного быстрее, убедитесь, что вы правильно набрали длину, очевидно, что ваш пример не имеет (m) выделен или определен массив удвоений. Теперь, если на самом деле у него будет только несколько удвоений, тогда цикл может оказаться быстрее. Но, как добраться до точки, где цикл заливки тени несколько инструкций настройки memset, как правило, используют большие и иногда выровненные куски для максимальной скорости.
Как обычно, проверяйте и измерьте. (хотя в этом случае вы попадаете в кеш, и измерение может оказаться фиктивным).
Ответ 13
Я думаю, вы имеете в виду
memset(d, 0, length * sizeof(d[0]))
и
for (int i = length; --i >= 0; ) d[i] = 0;
Лично я делаю одно, но я полагаю, что std::fill()
, вероятно, лучше.
Ответ 14
Если вам не требуется использовать STL...
double aValues [10];
ZeroMemory (aValues, sizeof(aValues));
ZeroMemory по крайней мере делает намерение понятным.
Ответ 15
В качестве альтернативы всем предложенным материалам я могу предложить вам НЕ устанавливать массив во все нули при запуске. Вместо этого установите значение в ноль только при первом доступе к значению в конкретной ячейке. Это остановит ваш вопрос и может быть быстрее.