Оператор Перегрузки Умножения Матриц

#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 , например, a std::invalid_argument , когда измерения не совпадают при умножении , т. Е. Когда m_ != right.n_ , и a std::range_error , когда аргумент operator [] выходит за рамки. (Проверки могут быть необязательными, активированными (например) для отладки с использованием if constexpr .)
  • Используйте a std::initializer_list или что-то подобное для инициализации, чтобы вы могли (например) const Matrix инициализировать в строке.
  • Всегда проверяйте свой код с помощью valgrind . (Совет: Расширяя, -g давайте valgrind также напечатаем номера строк, где произошло что-то неправильное (или где произошло соответствующее предыдущее распределение (de)).)
  • Код можно было бы сделать короче и элегантнее (не обязательно более эффективным; оптимизация компилятора в наши дни-это волшебство), если бы не использовать operator [] везде и вместо этого немного поразвлечься с арифметикой указателей.
  • Улучшите систему типов, чтобы (например) Matrix экземпляры с разными типами могли хорошо взаимодействовать друг с другом. Возможно, a Matrix<int> , умноженное на a Matrix<double> , может дать a Matrix<double> и т. Д. Можно также поддерживать умножение между скалярным значением и a Matrix . Или между а Matrix и а std::array и std::vector т. Д.