#c #matrix #operator-overloading
Вопрос:
Проблема, с которой я сталкиваюсь, заключается в том, как получить правильные числовые столбцы для прохождения для внутреннего наибольшего цикла K. Примером может служить матрица 2×3 и умножаемая матрица 3×2. Результатом должна быть матрица 2×2, но в настоящее время я не знаю, как отправить значение 2 перегруженной функции оператора. Это должно быть int k = 0; k
Matrix::Matrix(int row, int col)
{
rows = row;
cols = col;
cx = (float**)malloc(rows * sizeof(float*)); //initialize pointer to pointer matrix
for (int i = 0; i < rows; i )
*(cx i) = (float*)malloc(cols * sizeof(float));
}
Matrix Matrix::operator * (Matrix dx)
{
Matrix mult(rows, cols);
for (int i = 0; i < rows; i )
{
for (int j = 0; j < cols; j )
{
mult.cx[i][j] = 0;
for (int k = 0; k < ?;k ) //?????????????
{
mult.cx[i][j] = cx[i][k] * dx.cx[k][j];
}
}
}
mult.print();
return mu<
//calling
Matrix mult(rowA, colB);
mult = mat1 * mat2;
}
Комментарии:
1. Пожалуйста, не добавляйте в вопрос несколько языковых тегов. Используйте тег только для используемого вами языка.
2. Извините за скуку, но потребуется целая вечность, чтобы заставить работать класс matrix. Используйте BLAS, который является частью дистрибутива Boost.
3.
cx = (float**)malloc(rows * sizeof(float*));
является ли неопределенное поведение в C , почему вы его не используетеstd::vector
?
Ответ №1:
Правила линейной алгебры говорят, что результат должен иметь размеры строк x dx.cols
Matrix Matrix::operator * (Matrix dx)
{
Matrix mult(rows, dx.cols);
for (int i = 0; i < rows; i )
{
for (int j = 0; j < cols; j )
{
mult.cx[i][j] = 0;
for (int k = 0; k < cols;k ) //?????????????
{
mult.cx[i][j] = cx[i][k] * dx.cx[k][j];
}
}
}
mult.print();
return mu<
Ответ №2:
Несколько случайных подсказок:
- Ваш код в основном написан на C; он не использует (например) важные функции безопасности памяти из C . (Перегрузка операторов-единственная используемая функция, подобная C .) Я предлагаю вам немного больше использовать преимущества C .
- Строго избегайте
malloc()
в C . Используйтеstd::make_unique(...)
или, если другого способа нет, необработанныйnew
оператор. (Кстати, всегда есть другой способ.) В последнем случае убедитесь, что есть деструктор сdelete
илиdelete[]
. Использованиеmalloc()
в вашем фрагменте кода пахнет утечкой памяти. - Что может быть, то и
const
должно бытьconst
. Инициализируйте как можно больше членов класса в списке инициализаторов конструктора иconst
при необходимости создайте их. (Например,Matrix
размеры не меняются и должныconst
меняться .) - При написании класса, подобного контейнеру (которым
Matrix
в некотором смысле может быть a), не ограничивайте его одним типом данных; ваше будущее » я » поблагодарит вас. (Что делать, если вам нужно аdouble
вместо аfloat
? Будет ли это редактирование в одну строку или вы проведете всю ночь в поисках того, где забытыйfloat
съедает вашу точность?)
Вот быстрый и грязный пример, демонстрирующий матричное умножение:
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <memory>
namespace matrix {
using std::size_t;
template<typename Element>
class Matrix {
class Accessor {
public:
Accessor(const Matrixamp; mat, size_t m) : data_(amp;mat.data_[m * mat.n_]) {}
Elementamp; operator [](size_t n) { return data_[n]; }
const Elementamp; operator [](size_t n) const { return data_[n]; }
private:
Element *const data_;
};
public:
Matrix(size_t m, size_t n) : m_(m), n_(n),
data_(std::make_unique<Element[]>(m * n)) {}
Matrix(Matrix amp;amp;rv) : m_(rv.m_), n_(rv.n_), data_(std::move(rv.data_)) {}
Matrix operator *(const Matrixamp; right) {
Matrix result(m_, right.n_);
for (size_t i = 0; i < m_; i)
for (size_t j = 0; j < right.n_; j) {
result[i][j] = Element{};
for (size_t k = 0; k < n_; k) result[i][j] =
(*this)[i][k] * right[k][j];
}
return resu<
}
Accessor operator [](size_t m) { return Accessor(*this, m); }
const Accessor operator [](size_t m) const { return Accessor(*this, m); }
size_t m() const { return m_; }
size_t n() const { return n_; }
private:
const size_t m_;
const size_t n_;
std::unique_ptr<Element[]> data_;
};
template<typename Element>
std::ostreamamp; operator <<(std::ostream amp;out, const Matrix<Element> amp;mat) {
for (size_t i = 0; i < mat.m(); i) {
for (size_t j = 0; j < mat.n(); j) out << std::setw(4) << mat[i][j];
out << std::endl;
}
return out;
}
} // namespace matrix
int main() {
matrix::Matrix<int> m22{2, 2};
m22[0][0] = 0; // TODO: std::initializer_list
m22[0][1] = 1;
m22[1][0] = 2;
m22[1][1] = 3;
matrix::Matrix<int> m23{2, 3};
m23[0][0] = 0; // TODO: std::initializer_list
m23[0][1] = 1;
m23[0][2] = 2;
m23[1][0] = 3;
m23[1][1] = 4;
m23[1][2] = 5;
matrix::Matrix<int> m32{3, 2};
m32[0][0] = 5; // TODO: std::initializer_list
m32[0][1] = 4;
m32[1][0] = 3;
m32[1][1] = 2;
m32[2][0] = 1;
m32[2][1] = 0;
std::cout << "Original:nn";
std::cout << m22 << std::endl << m23 << std::endl << m32 << std::endl;
std::cout << "Multiplied:nn";
std::cout << m22 * m22 << std::endl
<< m22 * m23 << std::endl
<< m32 * m22 << std::endl
<< m23 * m32 << std::endl
<< m32 * m23 << std::endl;
}
Возможные улучшения и другие рекомендации:
- Добавьте проверки согласованности.
throw
, например, astd::invalid_argument
, когда измерения не совпадают при умножении , т. Е. Когдаm_ != right.n_
, и astd::range_error
, когда аргументoperator []
выходит за рамки. (Проверки могут быть необязательными, активированными (например) для отладки с использованиемif constexpr
.) - Используйте a
std::initializer_list
или что-то подобное для инициализации, чтобы вы могли (например)const Matrix
инициализировать в строке. - Всегда проверяйте свой код с помощью
valgrind
. (Совет: Расширяя,-g
давайтеvalgrind
также напечатаем номера строк, где произошло что-то неправильное (или где произошло соответствующее предыдущее распределение (de)).) - Код можно было бы сделать короче и элегантнее (не обязательно более эффективным; оптимизация компилятора в наши дни-это волшебство), если бы не использовать
operator []
везде и вместо этого немного поразвлечься с арифметикой указателей. - Улучшите систему типов, чтобы (например)
Matrix
экземпляры с разными типами могли хорошо взаимодействовать друг с другом. Возможно, aMatrix<int>
, умноженное на aMatrix<double>
, может дать aMatrix<double>
и т. Д. Можно также поддерживать умножение между скалярным значением и aMatrix
. Или между аMatrix
и аstd::array
иstd::vector
т. Д.