Memset массив int (16 бит) для максимального значения short
Не могу найти ответ на этот вопрос нигде, Как установить массив в максимальное значение типа массива? Я бы подумал ... --0--> будет работать, где ZBUFFER является 16-битным целочисленным массивом. Вместо этого я получаю-1.
кроме того, идея состоит в том, чтобы иметь эту работу как можно быстрее (это zbuffer, который должен инициализировать каждый кадр), поэтому, если есть лучший способ (и все еще так же быстро или быстрее), дайте мне знать.
изменить: как уточнение, мне нужна подпись массив.
9 ответов
на 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 );
это будет работать с любым типом.
на C, вам лучше держаться подальше memset
, который устанавливает значение байтов. Чтобы инициализировать массив других типов, чем char
(ev. unsigned
), вы должны прибегнуть к руководству for
петли.
-1 и 0xFFFF-это одно и то же в 16-битном целочисленном выражении с использованием представления дополнения two. Вы получаете только -1, потому что либо вы объявили свой массив как short
вместо unsigned short
. Или потому, что вы преобразуете значения в signed при их выводе.
кстати ваше предположение, что вы можете установить что-то, кроме байт использование memset неправильно. memset(ZBUFFER, 0xFF, size)
сделал бы то же самое.
В C++ вы можете заполнить массив с некоторым значением с .
std::fill(ZBUFFER, ZBUFFER+size, std::numeric_limits<short>::max());
это не быстрее и не медленнее, чем ваш текущий подход. Хотя у него есть преимущество работы.
не приписывайте скорость языку. Это для реализаций C. Существует несколько компиляторов, которые производят быстрый, оптимальный машинный код и компиляторы C, которые производят медленно, машинный код inoptimal. Аналогично для C++. "Быстрая, оптимальная" реализация может оптимизировать код, который медленно. Следовательно, не имеет смысла называть одно решение быстрее чем другой. Я буду говорить о достоверность, а потом я расскажу о производительность, незначительна она. Было бы лучше профилировать ваш код, чтобы убедиться, что это на самом деле узкое место, но давайте продолжим.
давайте рассмотрим наиболее разумный вариант, Во-первых: цикл, который копирует int
значения. Понятно, просто прочитав код, что цикл будет правильно назначать SHRT_MAX
для каждого int
товар. Ниже вы можете увидеть testcase этого цикла, который попытается использовать максимально возможный массив, выделяемый 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)
раза больше, чем цикл в моем первом примере. Учитывая, что моя реализация использует довольно оптимальный memset, вот вывод:
Copying into 1073741823 bytes
Done!
Process returned 0 (0x0) execution time : 1.060 s
Press any key to continue.
эти тесты, вероятно, будут отличаться, однако значительно. Я проверил их только один раз, чтобы получить приблизительное представление. Надеюсь, вы пришли к тому же выводу, что и я: общие компиляторы довольно хороши в оптимизации простых циклов, и здесь не стоит постулировать о микрооптимизации.
в итоге:
- не используйте memset для заполнения ints значениями (за исключением значения 0), потому что это не подходящий.
- не постулируйте об оптимизации до запуска тестов. Не запускайте тесты, пока у вас нет рабочего решения. Под рабочим решением я подразумеваю "программу, которая решает реальную проблему". После этого использовать профайлер, чтобы определить более значительные возможности для оптимизации!
это из-за дополнение. Вы должны изменить тип массива на unsigned short
, чтобы получить максимальное значение, или использовать 0x7FFF
.
for (int i = 0; i < SIZE / sizeof(short); ++i) {
ZBUFFER[i] = SHRT_MAX;
}
обратите внимание, что это не инициализирует последние пару байтов,if (SIZE % sizeof(short))
В 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.)
Как всегда, проверить свои выводы, если a) стоит оптимизировать эту часть программы и b) какая разница различные методы инициализации делает. Это будет зависеть от многих факторов. Для последних нескольких процентов производительности вам, возможно, придется прибегнуть к коду ассемблера.
#include <algorithm>
#include <limits>
std::fill_n(ZBUFFER, size, std::numeric_limits<FOO>::max())
здесь FOO
тип ZBUFFER
'S элементов.
когда вы говорите "memset", вам действительно нужно использовать эту функцию? Это только байт за байтом, поэтому он не будет работать со подписанными массивами.
Если вы хотите установить максимальное значение для каждого значения, вы должны использовать что-то вроде:
std::fill( ZBUFFER, ZBUFFER+len, std::numeric_limits<short>::max() )
, когда len
- это количество элементов (а не размер в байтах вашего массива)