Что быстрее/предпочтительнее: 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

В качестве альтернативы всем предложенным материалам я могу предложить вам НЕ устанавливать массив во все нули при запуске. Вместо этого установите значение в ноль только при первом доступе к значению в конкретной ячейке. Это остановит ваш вопрос и может быть быстрее.