Итак, у меня есть квадратная матрица с диагональными и антидиагональными элементами, отличными от нуля в векторе
vector<int> matrix = {1,2,3,4,5,6,7,8};
Матрица:
1 0 0 5
0 2 6 0
0 7 3 0
8 0 0 4
Я пытаюсь умножить это на другую матрицу
xmatrix — это класс матриц
Я пробовал вот так:
void xmatrix::operator*(const xmatrix& mat)
{
if(matrixSize != mat.getmatrixSize()) throw "Diff size";
int x;
for(int i = 0;i < matrixSize;i++){
for(int j = 0;j < matrixSize;j++){
x = 0;
for(int k = 0;k < matrixSize;k++){
x += getElement(i,k) * mat.getElement(k,j);
}
setElementMul(i,j,x);
}
}
}
Имена var и func ясно говорят сами за себя
ATM этот код отлично работает с первой половиной матрицы (умножить на себя)
41 0 0 225
0 46 294 0
0 35 219 0
40 0 0 216
какие еще способы могут работать нормально или как мне отредактировать этот код
1 ответ
Я считаю, что ваша проблема в том, что вы изменяете свою матрицу (множимое), когда выполняете умножение. Вот почему часть результата верна, а другая часть неверна. Например, правая верхняя ячейка (которая должна быть 25) оценивается из $ 41 * 5 + 5 * 4 = 225 $ где 41 (который должен быть 1) используется, потому что вы преждевременно установили эту ячейку из более ранней итерации.
Простым способом исправить это может быть использование промежуточной матрицы или буфера во время расчета. Однако если ваш xmatrix
class представляет матрицу, которая может быть только диагональной, антидиагональной или и тем, и другим, тогда вы можете использовать свойства диагональных матриц для оптимизации и упрощения вашего класса.
Если это действительно так, то вы можете просто представить всю матрицу ее диагональными и антидиагональными компонентами:
vector<int> diagonal;
vector<int> antidiag;
Что касается антидиагонального компонента, я обращусь к вашему примеру и буду использовать ориентацию от верхнего правого до нижнего левого (так что верхняя правая ячейка будет первой, а нижняя левая ячейка будет последней).
Теперь мы можем оптимизировать операцию умножения, отметив несколько свойств диагональных матриц. Рассмотрим диагональную матрицу $ A_x $ и антидиагональная матрица $ A_y $, оба размера $ n $. Пусть это антидиагональная и диагональная компоненты $ п * п $ матрица $ A $. Затем мы можем представить $ A $ такой, что $ A = A_x + A_y $. Однако это представление требует особой осторожности, когда $ n $ нечетный из-за общего среднего элемента. В таком случае мы поглощаем средний элемент диагональным компонентом и обнуляем средний элемент антидиагонального компонента. Итак, теперь у нас есть матрица умножаемых $ A $, мы используем аналогичные обозначения для представления матрицы множителей $ B $ такой, что $ B = B_x + B_y $. Используя несколько свойств матриц, мы можем показать, что умножение этих матриц представляет собой сумму диагональных и антидиагональных компонентов:
$$ AB = (A_x + A_y) (B_x + B_y) = A_xB_x + A_xB_y + A_yB_x + A_yB_y \ = (A_xB_x + A_yB_y) + (A_xB_y + A_yB_x) \ = ( text {[diagonal]}) + ( text {[anti-diagonal]}) $$
Теперь, когда мы поработали с математикой, мы можем использовать этот результат для реализации оптимизированного алгоритма умножения со сложностью времени $ O (п) $.
#include <iostream>
#include <vector>
class XMatrix
{
public:
XMatrix(const std::vector<int>& diagonal, const std::vector<int>& antidiag)
: diagonal(diagonal), antidiag(antidiag), size(diagonal.size())
{
if (diagonal.size() != antidiag.size())
throw;
if (this->size % 2 != 0) {
this->antidiag[this->size / 2] = 0;
}
}
/*
...
*/
XMatrix operator*(const XMatrix& m)
{
if (this->size != m.size)
throw;
std::vector<int> result_diagonal(this->size);
std::vector<int> result_antidiag(this->size);
for (int i = 0; i < this->size; ++i) {
result_diagonal[i]
= this->diagonal[i] * m.diagonal[i] +
this->antidiag[i] * m.antidiag[m.size-i-1];
result_antidiag[i]
= this->diagonal[i] * m.antidiag[i] +
this->antidiag[i] * m.diagonal[m.size-i-1];
}
return XMatrix(result_diagonal, result_antidiag);
}
void print() const
{
for (int row = 0; row < this->size; ++row) {
for (int col = 0; col < this->size; ++col) {
std::cout << 't';
if (row == col)
std::cout << this->diagonal[row];
else if (row == (this->size - col - 1))
std::cout << this->antidiag[row];
else
std::cout << '0';
}
std::cout << 'n';
}
}
private:
int size;
std::vector<int> diagonal;
std::vector<int> antidiag;
};
int main(int argc, char *argv[])
{
XMatrix matrix_A({1,2,3,4},{5,6,7,8});
XMatrix matrix_B = matrix_A * matrix_A;
matrix_B.print();
return 0;
}
Я изменил некоторые вещи по сравнению с вашим исходным кодом, чтобы проиллюстрировать все в этом ответе. Это может быть немного больше, чем вы просили относительно того, почему ваше матричное умножение работало только наполовину (если это все, о чем вы беспокоились, тогда не стесняйтесь игнорировать все после первых двух абзацев), но в любом случае я надеюсь, что смог помочь.