#c #pointers
#c #указатели
Вопрос:
Я пытаюсь реализовать код, показанный в этом pdf. Более точно (стр. 50):
#define SM (CLS / sizeof (double))
for (i = 0; i < N; i = SM)
for (j = 0; j < N; j = SM)
for (k = 0; k < N; k = SM)
for (i2 = 0, rres = amp;res[i][j],
rmul1 = amp;mul1[i][k]; i2 < SM;
i2, rres = N, rmul1 = N)
for (k2 = 0, rmul2 = amp;mul2[k][j];
k2 < SM; k2, rmul2 = N)
for (j2 = 0; j2 < SM; j2)
rres[j2] = rmul1[k2] * rmul2[j2];
Теперь, насколько я понимаю, rres
есть int*
, rmul2
и rmul1
тоже.
Должно ли это выглядеть так
int *rres;
int *rmul1;
int *rmul2;
for (i = 0; i < N; i = SM)
for (j = 0; j < N; j = SM)
for (k = 0; k < N; k = SM)
for (i2 = 0, *rres = amp;res[i][j],
*rmul1 = amp;mul1[i][k]; i2 < SM;
i2, rres = N, rmul1 = N)
for (k2 = 0, *rmul2 = amp;mul2[k][j];
k2 < SM; k2, rmul2 = N)
for (j2 = 0; j2 < SM; j2)
rres[j2] = rmul1[k2] * rmul2[j2];
Поскольку это кажется мне более или менее разумным, бит дает неправильные результаты. Например, если у меня есть две матрицы 2 x 2, случайные значения 0 или 1, я получаю:
-1520010527 23996350
212687419 207125308
что далеко не хорошо. Я предполагаю, что я использую *
неправильно, но я не могу сказать, где…
РЕДАКТИРОВАТЬ: объявление res
:
int **res = (int **)malloc(N * sizeof(int *));
for (int i = 0; i < N; i ) {
res[i] = (int *)malloc(N * sizeof(int));
}
for (int i = 0; i < N; i ) {
for (int j = 0; j < N; j ) {
res[i][j] = 0;
}
}
Комментарии:
1. Как
res
объявляется / инициализируется?2. @ScottHunter Я отредактировал вопрос.
3. В статье Дреппера пример кода предназначен для умножения двумерных массивов
double
s. В этом случае,rres
,rmul1
, иrmul2
все будут иметь типdouble *
. Что еще более важно, однако, Drepper — этоres
массив массивов, тогда как ваш — массив указателей . Это имеет огромное значение.4. @Nerwena, обсуждение, из которого вы взяли код, касается оптимизации для эффективного использования кэша. Это сильно зависит от расположения данных. Нет смысла выполнять упражнение, если вы не используете стиль компоновки данных, для которого предназначен код.
5.
*rres = amp;res[i][j]
должно выдать ошибку компиляции. Если этого не произойдет, измените настройки вашего компилятора, поскольку это заставляет вас тратить время, не имея этой информации
Ответ №1:
Ваше предположение о типе rres
rmul2
и rmul1
кажется неправильным: элементы матрицы, вероятно, имеют double
тип, а выражения в начальных предложениях for
циклов определенно не должны иметь инициала *
.
Тем не менее, этот код умножения матрицы должен работать одинаково для любого типа элемента, но оптимизация кэша, объясненная Ульрихом Дреппером, делает другое предположение: N
должно быть кратным SM
, и это вряд ли будет иметь место с #define SM (CLS / sizeof(double))
и N = 2
в вашем тестовом примере, что может объяснить ваши наблюдения.
Код должен быть:
#define SM (CLS / sizeof(double))
void matrix_multiply(double res[N][N], const double mul1[N][N], const double mul2[N][N]) {
size_t i, j, k, i2, j2, k2;
double *rres, *rmul1, *rmul2;
assert(N % SM == 0);
for (i = 0; i < N; i = SM) {
for (j = 0; j < N; j = SM) {
for (k = 0; k < N; k = SM) {
for (i2 = 0, rres = amp;res[i][j], rmul1 = amp;mul1[i][k];
i2 < SM; i2, rres = N, rmul1 = N) {
for (k2 = 0, rmul2 = amp;mul2[k][j];
k2 < SM; k2, rmul2 = N) {
for (j2 = 0; j2 < SM; j2)
rres[j2] = rmul1[k2] * rmul2[j2];
}
}
}
}
}
}
Комментарии:
1. Я полагаю, что вопрос OP заключается в том, почему они получают неправильные результаты, и это не решает эту проблему.
2. @JohnBollinger: вы правы, это не так, но я думаю, что я исправил ответ более вероятным объяснением.
3. О, глупая моя мысль, что я могу изменить это по своему усмотрению… Спасибо, это многое объясняет.