Что быстрее / предпочтительнее: memset или for, чтобы обнулить массив значений типа double?

Ваше понимание немного ошибочно. Алмазный оператор - хорошая функция, так как вам не нужно повторять себя. Имеет смысл определить тип один раз, когда вы объявляете тип, но просто не имеет смысла определять его снова с правой стороны. Принцип DRY.

Теперь, чтобы объяснить весь пух об определении типов. Вы правы, что тип удаляется во время выполнения, но как только вы хотите извлечь что-то из списка с определением типа, вы возвращаете его как тип, который вы определили при объявлении списка, иначе он потеряет все определенные функции и будет иметь только Объектные функции, за исключением случаев, когда вы отбрасываете извлеченный объект к его исходному типу, который иногда может быть очень сложным и приводит к исключению ClassCastException.

Использование List<String> list = new LinkedList() будет получать предупреждения rawtype.

20
задан emlai 12 March 2016 в 00:30
поделиться

15 ответов

Обратите внимание, что для memset вы должны передавать количество байтов, а не количество элементов, потому что это старая функция C:

memset(d, 0, sizeof(double)*length);

memset can будет быстрее, поскольку он написан на ассемблере, тогда как std :: fill - это шаблонная функция, которая просто выполняет внутренний цикл.

Но для обеспечения безопасности типов и более читаемого кода я бы рекомендовал std :: fill () - это способ работы c ++, и рассмотрите memset , если в этом месте кода требуется оптимизация производительности.

24
ответ дан 29 November 2019 в 00:39
поделиться

Я думаю, вы имеете в виду

memset(d, 0, length * sizeof(d[0]))

и

for (int i = length; --i >= 0; ) d[i] = 0;

Лично я использую любой из них, но полагаю, что std :: fill () , вероятно, лучше.

-2
ответ дан 29 November 2019 в 00:39
поделиться

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

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

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

-1
ответ дан 29 November 2019 в 00:39
поделиться

Если вам требуется не использовать STL ...

double aValues [10];
ZeroMemory (aValues, sizeof(aValues));

ZeroMemory по крайней мере проясняет намерение.

-1
ответ дан 29 November 2019 в 00:39
поделиться

В общем, memset будет намного быстрее, убедитесь, что вы правильно указали длину, очевидно, ваша В примере (m) не выделен или не определен массив значений типа double. Теперь, если он действительно закончится лишь несколькими дублями, цикл может оказаться быстрее. Но когда мы дойдем до точки, когда цикл заполнения будет затенять, несколько инструкций по настройке memset обычно будут использовать более крупные и иногда выровненные фрагменты для максимизации скорости.

Как обычно, тестируйте и измеряйте. (хотя в этом случае вы попадаете в кеш и измерение может оказаться подделкой).

0
ответ дан 29 November 2019 в 00:39
поделиться

memset (d, 10, 0) неверен, поскольку он обнуляет только 10 байтов. предпочитайте std :: fill, поскольку цель наиболее ясна.

1
ответ дан 29 November 2019 в 00:39
поделиться

Не забудьте сравнить правильно оптимизированный цикл for, если вы действительно заботитесь о производительности.

Некоторые варианты устройства Даффа, если массив достаточно длинный, и префикс --i без суффикса i-- (хотя большинство компиляторов, вероятно, исправят это автоматически.)

Хотя я бы сомневался, является ли это наиболее ценным для оптимизации. Действительно ли это узкое место для системы?

1
ответ дан 29 November 2019 в 00:39
поделиться

В дополнение к нескольким ошибкам и упущениям в вашем коде, использование memset не переносимо. Вы не можете предположить, что двойное значение со всеми нулевыми битами равно 0,0. Сначала исправьте код, а затем подумайте об оптимизации.

6
ответ дан 29 November 2019 в 00:39
поделиться
calloc(length, sizeof(double))

Согласно IEEE-754, битовое представление положительного нуля - это все нулевые биты, и нет ничего плохого в том, чтобы требовать соответствия IEEE-754. (Если вам нужно обнулить массив для его повторного использования, выберите одно из вышеперечисленных решений).

3
ответ дан 29 November 2019 в 00:39
поделиться
memset(d,0,10*sizeof(*d));

скорее всего будет быстрее. Как говорится, вы тоже можете

std::fill_n(d,10,0.);

, но, скорее всего, это более красивый способ сделать цикл.

4
ответ дан 29 November 2019 в 00:39
поделиться

Попробуйте это, хотя бы для того, чтобы быть крутым 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);
    }
}
12
ответ дан 29 November 2019 в 00:39
поделиться

Если вам действительно все равно, вы должны попробовать и измерить. Однако наиболее переносимым способом является использование std :: fill ():

std::fill( array, array + numberOfElements, 0.0 );
41
ответ дан 29 November 2019 в 00:39
поделиться

Согласно этой статье Википедии о IEEE 754-1975 64-битной с плавающей запятой битовая комбинация всех нулей действительно правильно инициализирует двойное значение 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 больше не понадобится. Я не использовал его в примере, потому что тогда кажется, что на ваш вопрос не будет ответа.

3
ответ дан 29 November 2019 в 00:39
поделиться

Пример не будет работать, потому что вам нужно выделить память для вашего массива. Вы можете сделать это в стеке или в куче.

Это пример того, как сделать это в стеке:

double d[50] = {0.0};

После этого memset не требуется.

3
ответ дан 29 November 2019 в 00:39
поделиться

Если длина цикла является целочисленным постоянным выражением, наиболее вероятным результатом будет то, что хороший оптимизатор распознает как цикл for, так и memset (0). В результате сгенерированная сборка будет практически одинаковой. Возможно, выбор регистров может отличаться или настройка. Но предельные затраты на удвоение действительно должны быть одинаковыми.

5
ответ дан 29 November 2019 в 00:39
поделиться