Memset для массива int (16 бит) в максимальном значении short

Кажется, нигде не могу найти ответ на этот вопрос,
Как мне установить массив для максимального значения типа массива?
Я бы подумал memset(ZBUFFER,0xFFFF,size) будет работать, где ZBUFFER является 16-битным целочисленным массивом. Вместо этого я получаю -1 с повсюду.

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

редактировать:
как пояснение, мне нужен массив int со знаком.

7

Решение

В C ++, вы бы использовали std :: fill и std :: numeric_limits.

#include <algorithm>
#include <iterator>
#include <limits>

template <typename IT>
void FillWithMax( IT first, IT last )
{
typedef typename std::iterator_traits<IT>::value_type T;
T const maxval = std::numeric_limits<T>::max();
std::fill( first, last, maxval );
}

size_t const size=32;
short ZBUFFER[size];
FillWithMax( ZBUFFER, &ZBUFFER[0]+size );

Это будет работать с любым типом.

В С, тебе лучше держаться подальше memset это устанавливает значение байтов. Инициализировать массив других типов, кроме char (Эв. unsigned), вы должны прибегнуть к руководству for петля.

9

Другие решения

-1 и 0xFFFF — это то же самое в 16-битном целом, используя представление дополнения до двух. Вы получаете только -1, потому что либо вы объявили свой массив как short вместо unsigned short, Или потому что вы конвертируете значения в подписанные при их выводе.

Кстати ваше предположение, что вы можете установить что-то кроме байтов использование memset неправильно. memset(ZBUFFER, 0xFF, size) сделал бы то же самое.

7

В C ++ вы можете заполнить массив некоторым значением с помощью std::fill алгоритм.

std::fill(ZBUFFER, ZBUFFER+size, std::numeric_limits<short>::max());

Это не быстрее и не медленнее, чем ваш нынешний подход. Это имеет преимущество работы, хотя.

4

Не приписывайте скорость языку. Это для реализаций C. Есть компиляторы C, которые производят быстрый, оптимальный машинный код, и C-компиляторы, которые создают медленный, неоптимальный машинный код. Аналогично для C ++. «Быстрая, оптимальная» реализация могла бы оптимизировать код, который кажется медленным. Следовательно, нет смысла называть одно решение Быстрее чем другой. Я поговорю о правильность, а потом я буду говорить о спектакль, каким бы незначительным это ни было. Лучше было бы профилировать ваш код, чтобы быть уверенным, что это действительно узкое место, но давайте продолжим.

Давайте сначала рассмотрим наиболее разумный вариант: цикл, который копирует int ценности. Понятно, просто читая код, который будет правильно назначать цикл SHRT_MAX для каждого int вещь. Вы можете увидеть тестовый пример этого цикла ниже, который попытается использовать максимально возможный массив, выделяемый malloc в это время.

#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
size_t size = SIZE_MAX;
volatile int *array = malloc(size);

/* Allocate largest array */
while (array == NULL && size > 0) {
size >>= 1;
array = malloc(size);
}

printf("Copying into %zu bytes\n", size);

for (size_t n = 0; n < size / sizeof *array; n++) {
array[n] = SHRT_MAX;
}

puts("Done!");
return 0;
}

Я запустил это в моей системе, скомпилирован с различными оптимизациями (-O3 -march=core2 -funroll-loops). Вот вывод:

Copying into 1073741823 bytes
Done!

Process returned 0 (0x0)   execution time : 1.094 s
Press any key to continue.

Обратите внимание на «время выполнения» … Это довольно быстро! Во всяком случае, узким местом здесь является локальность кэша такого большого массива, поэтому хороший программист попытается спроектировать системы, которые не используют так много памяти … Что ж, тогда давайте рассмотрим вариант memset. Вот цитата из руководство по memset:

Функция memset () копирует c (преобразуется в символ без знака) в
каждый из первых n байтов объекта, на который указывает s.

Следовательно, он преобразует 0xFFFF в беззнаковый символ (и потенциально усекает это значение), а затем присваивает преобразованное значение первому size байт. Это приводит к неправильному поведению. Мне не нравится полагаться на значение SHRT_MAX, которое будет представлено как последовательность байтов, хранящих значение (unsigned char) 0xFFFFпотому что это полагается на совпадение. Другими словами, главная проблема в том, что memset не подходит для вашей задачи. Не используйте это. Сказав это, вот тест, полученный из теста выше, который будет использоваться для проверки скорости memset:

#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
size_t size = SIZE_MAX;
volatile int *array = malloc(size);

/* Allocate largest array */
while (array == NULL && size > 0) {
size >>= 1;
array = malloc(size);
}

printf("Copying into %zu bytes\n", size);

memset(array, 0xFFFF, size);

puts("Done!");
return 0;
}

Тривиальный цикл memset для копирования байтов будет повторяться sizeof (int) раз больше, чем цикл в моем первом примере. Учитывая, что моя реализация использует довольно оптимальный набор записей, вот результат:

Copying into 1073741823 bytes
Done!

Process returned 0 (0x0)   execution time : 1.060 s
Press any key to continue.

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

В итоге:

  1. Не используйте memset для заполнения значений значениями (за исключением значения 0), потому что это не подходит.
  2. Не постулируйте об оптимизации перед запуском тестов. Не запускайте тесты, пока у вас нет рабочего решения. Под рабочим решением я имею в виду «программу, которая решает актуальную проблему». Как только у вас есть это, используйте свой профилировщик, чтобы определить более значительные возможности для оптимизации!
3

Это из-за дополнение двух. Вы должны изменить свой тип массива на unsigned short, чтобы получить максимальное значение, или используйте 0x7FFF,

2
for (int i = 0; i < SIZE / sizeof(short); ++i) {
ZBUFFER[i] = SHRT_MAX;
}

Обратите внимание, что это не инициализирует последние пару байтов, if (SIZE % sizeof(short))

2

В C вы можете сделать это как Адриан Панасюк сказал, и вы также можете развернуть цикл копирования. Развертывание означает копирование больших кусков за раз. Крайний конец разворачивания цикла — копирование всего кадра с нулевым кадром, например:

init()
{
for (int i = 0; i < sizeof(ZBUFFER) / sizeof(ZBUFFER[0]; ++i) {
empty_ZBUFFER[i] = SHRT_MAX;
}
}

фактическая очистка:

memcpy(ZBUFFER, empty_ZBUFFER, SIZE);

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

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

2
#include <algorithm>
#include <limits>

std::fill_n(ZBUFFER, size, std::numeric_limits<FOO>::max())

где FOO это тип ZBUFFERэлементы.

0
По вопросам рекламы [email protected]