【问题标题】:Operator Overloading Matrix Multiplication运算符重载矩阵乘法
【发布时间】:2021-10-17 18:26:41
【问题描述】:

我遇到的问题是如何为 K 的最内层循环获取正确的数字列。 一个例子是一个 2x3 矩阵和一个 3x2 矩阵相乘。 结果应该是一个 2x2 矩阵,但目前我不知道如何将 2 的值发送给运算符重载函数。 它应该是 诠释 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 mult;


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

【问题讨论】:

  • 请不要在一个问题中添加多个语言标签。仅使用您正在使用的语言的标签。
  • 很抱歉,这很无聊,但要让矩阵类正常工作需要一段时间。使用 BLAS,它是 Boost 发行版的一部分。
  • cx = (float**)malloc(rows * sizeof(float*)); 是 C++ 中的未定义行为你为什么不使用 std::vector ?

标签: c++ matrix operator-overloading


【解决方案1】:

线性代数规则说结果应该有维度 rows 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;

【讨论】:

    【解决方案2】:

    一些随机提示:

    • 你的代码基本上是C;它不使用(例如)来自 C++ 的重要内存安全特性。 (运算符重载是唯一使用的类似 C++ 的功能。)我建议您多利用 C++。
    • 严格避免在 C++ 中使用 malloc()。使用 std::make_unique(...) 或者,如果没有其他方法,则使用原始的 new 运算符。 (顺便说一句,总是另一种方式。)在后一种情况下,请确保有一个带有 delete 或 delete[] 的析构函数。在你的 sn-p 中使用malloc() 闻起来像是内存泄漏。
    • 可以是const应该是const。在构造函数的初始化器列表中初始化尽可能多的类成员,并在适当的情况下将它们设为const。 (例如,Matrix 尺寸不变,应为 const。)
    • 在编写类似容器的类(从某种意义上说可能是Matrix)时,不要将其限制为单一数据类型;你未来的自己会感谢你。 (如果您需要 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 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;
    }
    

    可能的改进和其他建议:

    • 添加一致性检查。 throw,例如,std::invalid_argument,当乘法时维度不匹配时,即当m_ != right.n_,当operator [] 获得越界参数时,std::range_error。 (检查可能是可选的,激活(例如)使用if constexpr 进行调试。)
    • 使用 std::initializer_list 或类似名称进行初始化,以便您可以(例如)内联初始化 const Matrix。
    • 始终使用valgrind 检查您的代码。 (提示:使用 -g 构建可以让 valgrind 也打印发生错误的行号(或发生相关的先前(取消)分配的位置)。)
    • 我可以通过不在任何地方使用operator [] 并通过指针算术获得一些乐趣来使代码更短、更优雅(不一定更高效;编译器优化现在很神奇)。
    • 使类型系统更好,以便(例如)Matrix 不同类型的实例可以很好地相互配合。也许Matrix&lt;int&gt; 乘以Matrix&lt;double&gt; 可以产生Matrix&lt;double&gt; 等等。还可以支持标量值和Matrix 之间的乘法。或者在Matrix 和std::array、std::vector 等之间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-29
      • 1970-01-01
      相关资源
      最近更新 更多