Привет, ЛОР.
В данный момент начинаю писать вечерами одну библиотеку на Си, которая будет делать кое-что из цифровой обработки сигналов.
Библиотеку хочу сделать переносимой (чтоб работала и на микроконтроллерах/DSP и на х86-64, и т.д.), поэтому готовый код от вендоров в топку.
И тут возникли вопросы про векторно-матричные операции:
-
Я правильно понимаю, что для минимизации кеш-промахов надо сделать так, чтобы на соседних итерациях циклов было как можно меньше «скачков» указателей?
-
В каком виде лучше (с точки зрения оптимизации вычислений компиляторами) писать доступ к массивам?
Так:
#define _DO_MM(name, op1, op2) \
void name(libInt sr, libInt scr, libInt sc, libFloat *res, libFloat *a, libFloat *b) \
{ \
libFloat *vr; \
libFloat *vb; \
libInt c; \
libInt r; \
\
assert(res); \
assert(a); \
assert(b); \
\
while (0 < sr--) \
{ \
r = scr; \
vb = b; \
c = sc; \
vr = res; \
while (0 < c--) \
{ \
*vr++ op1 *a * *vb++; \
} \
a++; \
\
while (0 < --r) \
{ \
c = sc; \
vr = res; \
while (0 < c--) \
{ \
*vr++ op2 *a * *vb++; \
} \
a++; \
} \
res += sc; \
} \
}
_DO_MM(lib_mm, =, +=)
_DO_MM(lib_add_mm, +=, +=)
_DO_MM(lib_sub_mm, -=, -=)
или Так:
#define _DO_MM(name, op1, op2) \
void name(libInt sr, libInt scr, libInt sc, libFloat *res, libFloat *a, libFloat *b) \
{ \
libInt i; \
libInt j; \
libInt k; \
\
assert(res); \
assert(a); \
assert(b); \
\
for (i = 0; i < sr; i++) \
{ \
for (k = 0; k < sc; k++) \
{ \
res[sc*i + k] op1 a[scr*i] * b[k]; \
} \
\
for (j = 1; j < scr; j++) \
{ \
for (k = 0; k < sc; k++) \
{ \
res[sc*i + k] op2 a[scr*i + j] * b[sc*j + k]; \
} \
} \
} \
}
_DO_MM(lib_mm, =, +=)
_DO_MM(lib_add_mm, +=, +=)
_DO_MM(lib_sub_mm, -=, -=)
З.Ы.: Больно не стукайте…