Home > other >  Trouble with matrix multiplication model
Trouble with matrix multiplication model

Time:03-31

For the past few hours I have been trying to build a C module that, upon requesting the input of the user on the size and contents of 2 matrices (restricted to ones that can be multiplied together), then proceeds to multiply them together and return the values of a third answer matrix. While the matrix input commands seem to work based on thorough testing, I can't seem to get a correct answer from my multiplication command, despite going through each step of the algorithm and how it corresponds to actual matrix multiplication. The first value of the answer matrix is correct, and then all succeeding values are incorrect by some factor. Does anyone have any insight as to what could be going wrong?

#include <iostream>
#include <cmath>
using namespace std;

int r, c, a1, a2, b1, b2;  //defines row and column indices
double m[1][1], m2[1][1], a[1][1];   //initializes matrices
double b;
int inflag = true;  
int repflag = false;

void defmatrix() {  //Defines the matrix size of the first inputted matrix
    cout << "Matrix Rows: ";
    cin >> r;
    cout << "Matrix Columns: ";
    cin >> c;
    
}

void fillmatrix() {  //Fills the matrix with automatic or user-inputted values
    if (inflag == true) {
        for (int i = 0; i < r; i  ) {
            for (int j = 0; j < c; j  ) {
               cout << "Number in row " << i   1 << " and column " << j   1 << ": ";
               cin >> b;
               m[i][j] = b;
            }
        }
    } else {
        for (int i = 0; i < r; i  ) {
            for (int j = 0; j < c; j  ) {
               m[i][j] = 1;
            }
        }
    }
    for (int i = 0; i < r; i  ) {
        for (int j = 0; j < c; j  ) {
           cout << m[i][j] << "   ";
        }
    }
}

void matrixmult() {  //Multiplication function for matrix math
    if (repflag == false) { 
        cout << "\n" << "Your second matrix will have " << c << " rows" << "\n";
        b1 = c;
        a1 = r;
        r = c; 
        cout << "Second matrix columns: ";
        cin >> c;
        a2 = c;
        double m2[r][c] = {};
        if (inflag == true) {
            for (int i = 0; i < r; i  ) {
                for (int j = 0; j < c; j  ) {
                    cout << "Number in row " << i   1 << " and column " << j   1 << ": ";
                    cin >> b;
                    m2[i][j] = b;
                }
            }
        } else {
            for (int i = 0; i < r; i  ) {
                for (int j = 0; j < c; j  ) {
                   m2[i][j] = 1;
                }
            }
        }
        a[a1][a2];
        for (int i = 0; i < a1; i  ) {
            for (int j = 0; j < a2; j  ) {
                b = 0;
                for (int d = 0; d < b1; d  ) {
                    b = b   (m[i][d] * m2[d][j]);
                }
                a[i][j] = b;
            }
        }
        for (int i = 0; i < a1; i  ) {
            for (int j = 0; j < a2; j  ) {
                cout << a[i][j] << "    ";
            }
        }
    } 
}

int main() {  //main file
    defmatrix();
    double m[r][c] = {};
    fillmatrix();
    matrixmult();
}

Thanks in advance!

CodePudding user response:

There is a problem in almost every line. It is easier to point out the good parts. The central for loop that calculates the matrix product seems OK. Most everything else needs to be thrown out and rewritten. This includes all declarations and all function interfaces.

Here's how I would start writing the program.

int main()
{
    int rows;
    int cols;
    int common_size; // columns in the matrix A and rows in the matrix B

    std::cout << "Enter number of rows in the result : ";
    std::cin  >> rows;
    std::cout << "Enter number of columns in the result : ";
    std::cin  >> cols;
    std::cout << "Enter the common size : ";
    std::cin  >> common_size;

Now we need to declare the matrices, but here comes a problem. One would naïvely want to write something like

    int a[rows][common_size], b[common_size][cols], c[rows][cols];

but alas, this is not legal C . This declaration may work with your compiler, or it may not. There are several ways to declare the matrices correctly. The simplest one is to reserve a fixed amount of memory for each one, and just use a portion:

    int a[10][10], b[10][10], c[10][10];

Naturally you need to check that the sizes provided by the user do not exceed 10.

Another method is to use the C version of variable length array, called [vector]. The declaration of a will look something like this:

    std::vector<std::vector<int>> a(rows, std::vector<int>(common_size));

With the second method, there is no real limitation on the matrix sizes.

Neither method is adequate for any real software, but they are enough to complete your C exercise. Real software uses more advanced C concepts like classes to define matrices. Just something to be aware of.

I will not continue writing it at the same level of detail. This is your task. I will just show what the rest of main could look like.

    input_matrix(a, rows, common_size);
    input_matrix(b, common_size, cols);
    multiply_matrices(a, b, c, rows, common_size, cols);
    print_matrix(c, rows, cols);

Note function calls using arguments. Implement these functions, and you are good to go. Note, if you choose vectors, you will need to pass some arguments by reference. In this case you could also write the functions this way:

    input_matrix(a);
    input_matrix(b);
    c = multiply_matrices(a, b);
    print_matrix(c);

but this is a talk for another day.

CodePudding user response:

Although you're asking to find mistakes in your code, as your task is interesting I decided to implement my own solution from scratch for you. Even if it is unacceptable answer, still it might be useful for educational purpose.

I made code in a form of class Matrix that supports multiplication operation between two matching matrices like A *= B;. As you did, I also implemented two methods .Input() and .Output() that correspondingly read matrix from std::cin and output to std::cout.

As a bonus there is also a method .At(i, j) that returns reference to element of a matrix with bounds checking, similar to std::vector.

Sure class can be extended to many other matrices operations (like addition A = B; or subtraction A -= B;), but I limited my class to only those things that you used in your original code.

To do what you wanted using my class is simple as few lines of code (that are located further in main() function of following code snippet):

Matrix A, B;
A.Input(); B.Input();
A *= B;
A.Output();

Full code:

Try it online!

#include <stdexcept>
#include <vector>
#include <sstream>
#include <iomanip>
#include <iostream>

#define ASSERT_MSG(cond, msg) { if (!(cond)) throw std::runtime_error("Assertion (" #cond ") failed at line "   std::to_string(__LINE__)   "! Msg: '"   std::string(msg)   "'."); }
#define ASSERT(cond) ASSERT_MSG(cond, "")

class Matrix {
public:
    using FloatT = double;
    Matrix(size_t rows = 0, size_t cols = 0)
        : rows_(rows), cols_(cols) {
        Clear();
    }
    Matrix & Clear() {
        m_.clear();
        m_.resize(rows_ * cols_);
        return *this;
    }
    size_t Rows() const { return rows_; }
    size_t Cols() const { return cols_; }
    Matrix & operator = (Matrix && other) {
        rows_ = other.rows_;
        cols_ = other.cols_;
        m_ = std::move(other.m_);
        other.rows_ = 0;
        other.cols_ = 0;
        return *this;
    }
    FloatT & operator() (size_t i, size_t j) {
        return m_[i * cols_   j];
    }
    FloatT const & operator() (size_t i, size_t j) const {
        return const_cast<Matrix &>(*this)(i, j);
    }
    FloatT & At(size_t i, size_t j) {
        ASSERT_MSG(i < rows_ && j < cols_,
            "Matrix index ("   std::to_string(i)   ", "   std::to_string(j)  
            ") out of bounds ("   std::to_string(rows_)   ", "   std::to_string(cols_)   ")!");
        return (*this)(i, j);
    }
    FloatT const & At(size_t i, size_t j) const {
        return const_cast<Matrix &>(*this).At(i, j);
    }
    Matrix & operator *= (Matrix const & B) {
        Matrix const & A = *this;
        ASSERT_MSG(A.Cols() == B.Rows(),
            "Number of A.Cols "   std::to_string(A.Cols())  
            " and B.Rows "   std::to_string(B.Rows())   " don't match!");
        Matrix C(A.Rows(), B.Cols());

        for (size_t i = 0; i < A.Rows();   i)
            for (size_t j = 0; j < B.Cols();   j) {
                FloatT sum = 0;
                for (size_t k = 0; k < A.Cols();   k)
                    sum  = A(i, k) * B(k, j);
                C(i, j) = sum;
            }

        *this = std::move(C);
        return *this;
    }
    Matrix & Input() {
        std::cout << "Enter number of rows and columns: ";
        std::cin >> rows_ >> cols_;
        Clear();
        std::cout << "Enter all matrix elements:" << std::endl;
        for (size_t i = 0; i < rows_;   i)
            for (size_t j = 0; j < cols_;   j)
                std::cin >> (*this)(i, j);
        return *this;
    }
    Matrix const & Output(size_t precision = 6) const {
        std::vector<std::vector<std::string>> cells(Rows(),
            std::vector<std::string>(Cols()));

        std::ostringstream ss;
        size_t max_len = 0;
        for (size_t i = 0; i < Rows();   i)
            for (size_t j = 0; j < Cols();   j) {
                ss.str("");
                ss << std::fixed << std::setprecision(precision)
                    << (*this)(i, j);
                cells[i][j] = ss.str();
                max_len = std::max(max_len, cells[i][j].size());
            }

        for (auto const & row: cells) {
            for (auto const & cell: row)
                std::cout << std::string(max_len - cell.size()   1, ' ')
                    << cell;
            std::cout << std::endl;
        }

        return *this;
    }
private:
    size_t rows_ = 0, cols_ = 0;
    std::vector<FloatT> m_;
};

int main() {
    try {
        Matrix A, B;
        A.Input();
        B.Input();
        A *= B;
        A.Output();
        return 0;
    } catch (std::exception const & ex) {
        std::cout << "Exception: " << ex.what() << std::endl;
        return -1;
    }
}

Input:

Enter number of rows and columns: 3 2
Enter all matrix elements:
1.01 2.02
3.03 4.04
5.05 6.06

Enter number of rows and columns: 2 4
Enter all matrix elements:
 7.07  8.08  9.09 10.10
11.11 12.12 13.13 14.14

Output:

  29.582900  32.643200  35.703500  38.763800
  66.306500  73.447200  80.587900  87.728600
 103.030100 114.251200 125.472300 136.693400
  • Related