Я пишу небольшую программу, в которой мне приходилось использовать систему координат на борту (x/y в 2d-массиве) и думал, следует ли использовать индексирование как array[x][y]
, что кажется мне более естественным или array[y][x]
, который будет лучше соответствовать тому, как массив представлен в памяти. Я считаю, что оба эти метода будут работать, если я буду последовательно, и это просто проблема с именами, но как насчет соглашений при написании больших программ?
Что такое соглашение индексации 2D-массива с координатами x/y в C?
Ответ 1
В моей области (обработка изображений) соглашение [y][x]
более обычное. Независимо от того, что вы делаете, будьте последовательны и хорошо документируйте.
Ответ 2
Вы также должны рассмотреть, что вы собираетесь делать с этими массивами, и важно ли это критически важно для времени.
Как указано в комментариях: Элемент a[r][c+1]
находится рядом с a[r][c]
. Этот факт может оказать значительное влияние на производительность при повторении более крупных массивов. Правильный порядок обхода приведет к тому, что линии кэша будут полностью использованы: при обращении к одному индексу массива он считается "вероятным", после чего будет доступен следующий индекс, и весь блок памяти будет загружен в кэш. Если после этого вы получаете доступ к совершенно другому местоположению памяти (а именно к одному в следующей строке), то пропускная способность этого кэша пропадает.
Если возможно, вы должны попытаться использовать порядок обхода, соответствующий размеру макета.
(Конечно, это касается "условностей" и "привычек": при записи доступа к массиву, например, a[row][col]
, это обычно интерпретируется как доступ к массиву a[y][x]
из-за соглашения x - ось горизонтальная, а ось y - вертикальная...)
Вот небольшой пример, демонстрирующий потенциальное влияние "неправильного" порядка обхода:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
float computeSumRowMajor(float **array, int rows, int cols)
{
float sum = 0;
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
sum += array[r][c];
}
}
return sum;
}
float computeSumColMajor(float **array, int rows, int cols)
{
float sum = 0;
for (int c=0; c<cols; c++)
{
for (int r=0; r<rows; r++)
{
sum += array[r][c];
}
}
return sum;
}
int main()
{
int rows = 5000;
int cols = 5000;
float **array = (float**)malloc(rows*sizeof(float*));
for (int r=0; r<rows; r++)
{
array[r] = (float*)malloc(cols*sizeof(float));
for (int c=0; c<cols; c++)
{
array[r][c] = 0.01f;
}
}
clock_t start, end;
start = clock();
float sumRowMajor = 0;
for (int i=0; i<10; i++)
{
sumRowMajor += computeSumRowMajor(array, rows, cols);
}
end = clock();
double timeRowMajor = ((double) (end - start)) / CLOCKS_PER_SEC;
start = clock();
float sumColMajor = 0;
for (int i=0; i<10; i++)
{
sumColMajor += computeSumColMajor(array, rows, cols);
}
end = clock();
double timeColMajor = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("Row major %f, result %f\n", timeRowMajor, sumRowMajor);
printf("Col major %f, result %f\n", timeColMajor, sumColMajor);
return 0;
}
(извинения, если я нарушил некоторые лучшие практики здесь, я обычно парень Java...)
Для меня доступ к ряду строк почти на порядок быстрее, чем доступ к столбцу. Конечно, точные цифры будут сильно зависеть от целевой системы, но общая проблема должна быть одинаковой для всех целей.