Матрицы: два индекса, один адрес
Матрица — это сетка чисел, расположенных в строках и столбцах. Строка — это одна горизонтальная линия сетки, читаемая слева направо. Столбец — это одна вертикальная линия сетки, читаемая сверху вниз. В памяти нет понятия строк или столбцов. Это одна длинная линия байтов, тот же вид вектора, что рассматривался в предыдущем уроке. Чтобы сохранить матрицу, её строки и столбцы должны быть размещены один за другим в этой единственной линии. Обычный выбор — порядок row-major: сохранить каждое число первой строки, затем каждое число второй строки, и продолжать, пока каждая строка не будет размещена.
Два индекса, один адрес
Позиция элемента в матрице задаётся двумя индексами: индексом строки, к которой он принадлежит, и индексом столбца, к которому он принадлежит. Отсчёт обоих начинается с 0, так же как индексы работали в уроке о векторах. Память хранит одну плоскую последовательность чисел, поэтому оба индекса сначала нужно объединить в один уплощённый индекс: умножьте индекс строки на число столбцов матрицы, затем прибавьте индекс столбца. Оттуда уплощённый индекс становится байтовым адресом так же, как индекс вектора: address = base + index * 4.
mul t4, t1, t3 # t4 = индекс строки * количество столбцовadd t4, t4, t2 # t4 = that + индекс столбца (уплощённый индекс)slli t4, t4, 2 # t4 = смещение в байтах = индекс * 4add t5, t0, t4 # t5 = адрес элемента в этой строке и столбцеlw t5, 0(t5) # t5 = значение по этому адресу
умножает индекс строки на число столбцов. В уроке о векторах умножение можно было выполнить сдвигом, потому что 4 — степень двойки, но число столбцов матрицы обычно таковой не является, поэтому здесь используется вместо . Индекс столбца прибавляется, а результат масштабируется на 4 с помощью ещё одного (4 — степень двойки, так что сдвиг для этой части всё ещё работает). Это даёт байтовое смещение элемента в заданной строке и столбце.
Строка 0, столбец 0 соответствует индексу 0.
.data-раскладка вашей программы и ваше собственное её чтение, используя арифметику , и , показанную выше. Как только сетка и уплощённая строка понимаются как одна вещь, показанная дважды, тот же шаблон охватывает любую сетку данных: строки пикселей изображения, игровое поле или электронную таблицу. Каждая из них — один массив, доступ к которому осуществляется с одним дополнительным умножением.Суммирование матрицы
.datam: .word 1, 2, 3, 4, 5, 6, 7, 8, 9 # матрица 3x3, хранится по строкам.textla t0, m # базовый адресli t1, 3 # количество строкli t2, 3 # количество столбцовli t3, 0 # текущий индекс строки, начинается с 0li s0, 0 # текущая суммаrow_loop:beq t3, t1, row_doneli t4, 0 # текущий индекс столбца, начинается с 0col_loop:beq t4, t2, col_donemul t5, t3, t2 # индекс строки * количество столбцовadd t5, t5, t4 # + индекс столбца = развёрнутый индексslli t5, t5, 2 # смещение в байтах = индекс * 4add t6, t0, t5 # адрес элемента в этой строке и столбцеlw t6, 0(t6) # значение по этому адресуadd s0, s0, t6 # итог += элементaddi t4, t4, 1 # переходит к следующему столбцуj col_loopcol_done:addi t3, t3, 1 # переходит к следующей строкеj row_looprow_done:mv a0, s0 # печатает итог: 1+2+...+9 = 45li a7, 1ecallli a7, 10ecall
Два вложенных цикла индексируют матрицу. Внешний цикл выбирает строку, а внутренний выбирает столбец в этой строке. умножает индекс строки на число столбцов. Прибавление индекса столбца и масштабирование на 4 даёт адрес этого элемента. Значение, хранящееся по этому адресу, загружается и прибавляется к текущей сумме. Когда внутренний цикл завершает строку, внешний цикл переходит к следующей строке, пока все 3 строки не будут обработаны.
