简体   繁体   English

运算符重载矩阵乘法

[英]Operator Overloading Matrix Multiplication

The issue I am having is how to get the correct number columns to go through for the inner most loop of K. An example is a 2x3 matrix and a 3x2 matrix being multiplied.我遇到的问题是如何为 K 的最内部循环获得正确的列数。一个例子是一个 2x3 矩阵和一个 3x2 矩阵相乘。 The result should be a 2x2 matrix, but currently I dont know how to send the value of 2 to the operator overloaded function.结果应该是一个 2x2 矩阵,但目前我不知道如何将 2 的值发送给运算符重载函数。 It should be int k = 0;它应该是 int k = 0; k < columns of first matrix;k++ k < 第一个矩阵的列;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 mult;


 //calling
  Matrix mult(rowA, colB);
           mult = mat1 * mat2;
}

Linear algebra rules say the result should have dimensions rows x dx.cols线性代数规则说结果应该有维度行 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 mult;

A few random hints:一些随机提示:

  • Your code is basically C;你的代码基本上是 C; it doesn't use (eg) important memory-safety features from C++.它不使用(例如)来自 C++ 的重要内存安全特性。 (Operator overloading is the only C++-like feature in use.) I suggest that you take advantage of C++ a bit more. (运算符重载是唯一使用的类似 C++ 的特性。)我建议您多利用 C++。
  • Strictly avoid malloc() in C++.在 C++ 中严格避免malloc() Use std::make_unique(...) or, if there is no other way, a raw new operator.使用std::make_unique(...)或者,如果没有其他方法,则使用原始的new运算符。 (BTW, there is always another way.) In the latter case, make sure there is a destructor with a delete or delete[] . (顺便说一句,总有另一种方式。)在后一种情况下,请确保有一个带有deletedelete[]的析构函数。 The use of malloc() in your snippet smells like a memory leak.在您的代码片段中使用malloc()闻起来像内存泄漏。
  • What can be const should be const .什么可以const应该const Initialize as many class members as possible in the constructor's initializer list and make them const if appropriate.在构造函数的初始化列表中初始化尽可能多的类成员,并在适当的情况下使它们成为const (For example, Matrix dimensions don't change and should be const .) (例如, Matrix维度不会改变,应该是const 。)
  • When writing a container-like class (which a Matrix may be, in a sense), don't restrict it to a single data type;在编写类容器类(某种意义上可能是Matrix )时,不要将其限制为单一数据类型; your future self will thank you.你未来的自己会感谢你。 (What if you need a double instead of a float ? Is it going to be a one-liner edit or an all-nighter spent searching where a forgotten float eats away your precision?) (如果您需要double而不是float怎么办?它是单行编辑还是通宵搜索被遗忘的float您的精度?)

Here's a quick and dirty runnable example showing matrix multiplication:这是一个显示矩阵乘法的快速而肮脏的可运行示例:

#include <cstddef>
#include <iomanip>
#include <iostream>
#include <memory>

namespace matrix {
using std::size_t;

template<typename Element>
class Matrix {
  class Accessor {
   public:
    Accessor(const Matrix& mat, size_t m) : data_(&mat.data_[m * mat.n_]) {}
    Element& operator [](size_t n) { return data_[n]; }
    const Element& 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 &&rv) : m_(rv.m_), n_(rv.n_), data_(std::move(rv.data_)) {}

  Matrix operator *(const Matrix& 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 result;
  }

  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::ostream& operator <<(std::ostream &out, const Matrix<Element> &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:\n\n";
  std::cout << m22 << std::endl << m23 << std::endl << m32 << std::endl;

  std::cout << "Multiplied:\n\n";
  std::cout << m22 * m22 << std::endl
            << m22 * m23 << std::endl
            << m32 * m22 << std::endl
            << m23 * m32 << std::endl
            << m32 * m23 << std::endl;
}

Possible improvements and other recommendations:可能的改进和其他建议:

  • Add consistency checks.添加一致性检查。 throw , for example, a std::invalid_argument when dimensions don't match on multiplication, ie when m_ != right.n_ , and a std::range_error when the operator [] gets an out-of-bounds argument.例如,当乘法时维度不匹配时throw std::invalid_argument ,即当m_ != right.n_ ,当operator []获得越界参数时std::range_error (The checks may be optional, activated (eg) for debugging using an if constexpr .) (检查可能是可选的,激活(例如)使用if constexpr进行调试。)
  • Use a std::initializer_list or the like for initialization, so that you can have (eg) a const Matrix initialized in-line.使用std::initializer_list等进行初始化,以便您可以(例如)内联初始化const Matrix
  • Always check your code using valgrind .始终使用valgrind检查您的代码。 (Tip: Buliding with -g lets valgrind print also the line numbers where something wrong happened (or where a relevant preceding (de)allocation had happened).) (提示:使用-g构建可以让valgrind还打印发生错误的行号(或发生相关的先前(解除)分配的位置)。)
  • The code could me made shorter and more elegant (not necessarily more efficient; compiler optimizations are magic nowadays) by not using operator [] everywhere and having some fun with pointer arithmetics instead.我可以通过不在任何地方使用operator []而使用指针算术来获得一些乐趣,从而使代码更短、更优雅(不一定更有效;编译器优化现在很神奇)。
  • Make the type system better, so that (eg) Matrix instances with different types can play well with each other.使类型系统更好,以便(例如)具有不同类型的Matrix实例可以很好地相互配合。 Perhaps a Matrix<int> multiplied by a Matrix<double> could yield a Matrix<double> etc. One could also support multiplication between a scalar value and a Matrix .也许Matrix<int>乘以Matrix<double>可以产生Matrix<double>等。还可以支持标量值和Matrix之间的乘法。 Or between a Matrix and a std::array , std::vector etc.或者在Matrixstd::arraystd::vector等之间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM