Возможно, вам понадобится четыре цикла - два для итерации по блокам, а затем еще два для выполнения транспонирования-копии одного блока.Предполагая для простоты размер блока, который делит размер матрицы, я думаю, что-то вроде этого, хотя я бы хотел нарисовать несколько картинок на обороте конвертов, чтобы быть уверенным:
for (int i = 0; i < n; i += blocksize) {
for (int j = 0; j < n; j += blocksize) {
// transpose the block beginning at [i,j]
for (int k = i; k < i + blocksize; ++k) {
for (int l = j; l < j + blocksize; ++l) {
dst[k + l*n] = src[l + k*n];
}
}
}
}
Важное дальнейшеепонимание состоит в том, что на самом деле для этого существует алгоритм кеширования (см. http://en.wikipedia.org/wiki/Cache-oblivious_algorithm,, который использует именно эту проблему в качестве примера).Неформальное определение «не обращающего внимания на кэш» заключается в том, что вам не нужно экспериментировать с настройкой каких-либо параметров (в данном случае размера блоков), чтобы достичь хорошей / оптимальной производительности кэша.Решением в этом случае является транспонирование путем рекурсивного деления матрицы пополам и перемещения половин в их правильное положение в месте назначения.
Каким бы ни был размер кэша, эта рекурсия использует его в своих интересах.Я ожидаю, что по сравнению с вашей стратегией возникнут некоторые дополнительные издержки на управление, заключающиеся в том, чтобы использовать эксперименты с производительностью, чтобы, по сути, перейти прямо к той точке рекурсии, в которой кэш действительно срабатывает, и не идти дальше.С другой стороны, ваши эксперименты с производительностью могут дать вам ответ, который работает на вашей машине, но не на машинах ваших клиентов.