Что такое чередующийся массив?
Существует также аналог, который называется массивом плотности. Что это значит? Я сделал поиск, но не получил точной информации.
Ответы
Ответ 1
Чтобы сделать шаг, выполните "длинные шаги"
thefreedictionary.com/stride
Для массива это означало бы, что присутствуют только некоторые из элементов, как и каждый 10-й элемент. Затем вы можете сэкономить место, не сохраняя пустые элементы между ними.
Плотный массив будет таким, где присутствуют многие, если не все, элементы, поэтому между элементами нет пустого пространства.
Ответ 2
Скажите, что у вас есть структура
struct SomeStruct {
int someField;
int someUselessField;
int anotherUselessField;
};
и массив
struct SomeStruct array[10];
Затем, если вы посмотрите на все someField
в этом массиве, их можно считать самим массивом, но они не занимают последующих ячеек памяти, поэтому этот массив является strided. Шаг здесь sizeof(SomeStruct)
, т.е. Расстояние между двумя последующими элементами перечеркнутой решетки.
Редкий массив, упомянутый здесь, является более общим понятием и фактически другим: чередующийся массив не содержит нулей в пропущенных ячейках памяти, они просто не являются частью массива.
Strided array - это обобщение обычных (плотных) массивов, когда stride != sizeof(element)
.
Ответ 3
Если вы хотите работать с подмножеством 2D-массива, вам нужно знать "шаг" массива. Предположим, что у вас есть:
int array[4][5];
и вы хотите работать с подмножеством элементов, начиная с массива [1] [1], до массива [2,3].
Это, по существу, ядро диаграммы ниже:
+-----+-----+-----+-----+-----+
| 0,0 | 0,1 | 0,2 | 0,3 | 0,4 |
+-----+=====+=====+=====+-----+
| 1,0 [ 1,1 | 1,2 | 1,3 ] 1,4 |
+-----+=====+=====+=====+-----+
| 2,0 [ 2,1 | 2,2 | 2,3 ] 2,4 |
+-----+=====+=====+=====+-----+
| 3,0 | 3,1 | 3,2 | 3,3 | 3,4 |
+-----+-----+-----+-----+-----+
Чтобы получить доступ к подмножеству массива в функции точно, вам нужно указать вызываемой функции шаг массива:
int summer(int *array, int rows, int cols, int stride)
{
int sum = 0;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
sum += array[i * stride + j];
return(sum);
}
и вызов:
int sum = summer(&array[1][1], 2, 3, 5);
Ответ 4
Я добавляю еще один ответ здесь, так как я не нашел ни одного из существующих удовлетворительным.
Wikipedia объясняет концепцию шага, а также пишет, что "шаг не может быть меньше размера элемента (это будет означать, что элементы перекрывается), но может быть больше (что указывает дополнительное пространство между элементами)".
Однако из информации, которую я нашел, массивы с чередованием допускают именно это: сохраняют память, позволяя шагу быть нулевым или отрицательным.
Направленные массивы
Компиляция APL для JavaScript объясняет чередующиеся массивы как способ представления многомерных массивов с данными и шагами, в отличие от типичного "прямоугольного" представления массивы, которые предполагают неявный шаг 1. Он допускает как положительный, отрицательный, так и нулевой шаг. Зачем? Это позволяет многим операциям изменять только шаг и форму, а не базовые данные, что позволяет эффективно манипулировать большими массивами.
Преимущество этого чередующегося представления становится очевидным при работе с большими объемами данных. Функции, такие как transpose (⍉⍵
), reverse (⌽⍵
) или drop (⍺↓⍵
), могут повторно использовать массив данных и только заботиться о том, чтобы придать их новую форму, шаг и смещение. Реконструированный скаляр, например. 1000000⍴0
, может занимать только постоянный объем памяти, используя тот факт, что шагами могут быть 0.
Я не разработал точно, как эти операции будут реализованы как операции по шагу и форме, но легко видеть, что изменение только этих, а не базовых данных было бы намного дешевле с точки зрения вычислений. Тем не менее, стоит иметь в виду, что чересстрочное представление может отрицательно повлиять на местоположение кэша, поэтому в зависимости от варианта использования лучше использовать обычные прямоугольные массивы.
Ответ 5
В высокооптимизированном коде одна разумная технология coomon заключается в вставке дополнений в массивы. Это означает, что N-й логический элемент больше не находится в смещении N*sizeof(T)
. Причиной этого может быть оптимизация, так это то, что некоторые кеши ограничены ассоциативностью. Это означает, что они не могут кэшировать оба массива [i] и array [j] для некоторых пар i, j. Если алгоритм, работающий на плотном массиве, будет использовать многие из таких пар, добавление некоторых дополнений может уменьшить это.
Обычный случай, когда это происходит, заключается в обработке изображений. Изображение часто имеет ширину линии 512 байтов или другое "двоичное число раундов", а многие подпрограммы обработки изображений используют 3x3 окрестности пикселя. В результате вы можете получить довольно много выходов из кэша на некоторых архитектурах кэшей. Вставляя "странное" количество поддельных пикселей (например, 3) в конце каждой строки, вы изменяете "шаг" и там меньше помех кэша между соседними строками.
Это очень специфично для процессора, поэтому здесь нет общих советов.
Ответ 6
Возможность 1: Stride описывает буферный массив для чтения оптимизированного массива
Когда вы используете метод
хранить многомерные массивы в линейном хранилище. Шаг описывает размер в каждом измерении буфера, который поможет вам прочитать этот массив. Изображение взято из Nd4j (дополнительная информация о Stride)
![Stride as buffer of the array]()
Возможность 2 (нижний уровень): Stride - это расстояние между смежными элементами массива
Это означает, что адреса элементов с индексами 0 и 1 не будут непрерывными в памяти, если вы не используете блок Stride. Большее значение будет иметь более отдаленные объекты в памяти.
Это полезно на низком уровне (оптимизация длины слова, перекрывающиеся массивы, оптимизация кеша). См. wikipedia.