I don't really know how to check the size of both matrices, if they are appropriate to be added.
Here's my code, which is currently running without errors:
matrix operator+(const matrix & mat){
matrix add;
add.mSize = mat.mSize;
add.mP = new int[add.mSize * add.mSize];
for(int i = 0; i < add.mSize * add.mSize; i++){
add.mP[i] = mP[i] + mat.mP[i];
}
return add;
}
A general 2d matrix has two different dimensions, rows and columns (unless it is the particular case of a square matrix).
In the general case, your code could be:
#include <stdexcept>
class matrix
{
public:
matrix(int rows, int columns) :
mRows(rows), mColumns(columns), mP(NULL)
{
mP = new double[mRows * mColumns];
for (int i = 0; i < mRows * mColumns; i++)
mP[i] = 0.0;
}
matrix(const matrix& other) :
mRows(other.mRows), mColumns(other.mColumns), mP(NULL)
{
mP = new double[mRows * mColumns];
for (int i = 0; i < mRows * mColumns; i++)
mP[i] = other.mP[i];
}
~matrix()
{
delete[] mP;
}
const double* operator[] (int row) const {
return &mP[row * mColumns];
}
double* operator[] (int row) {
return &mP[row * mColumns];
}
matrix& operator=(const matrix& other) {
if (this == &other) return *this;
if ((mRows != other.mRows) || (mColumns != other.mColumns)) throw std::invalid_argument( "dimensions don't match" );
for (int r = 0; r < mRows; r++) {
for (int c = 0; c < mColumns; c++) {
(*this)[r][c] = other[r][c];
}
}
return *this;
}
matrix& operator+=(const matrix& other) {
if ((mRows != other.mRows) || (mColumns != other.mColumns)) throw std::invalid_argument( "dimensions don't match" );
for (int r = 0; r < mRows; r++) {
for (int c = 0; c < mColumns; c++) {
(*this)[r][c] += other[r][c];
}
}
return *this;
}
private:
int mRows;
int mColumns;
double *mP;
};
inline matrix operator+(matrix lhs, const matrix& rhs)
{
lhs += rhs;
return lhs;
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have a class for complex numbers whose data members are im (the imaginary part) and re (the real part). Now I want to sum 2 matrix that come from the class Matrix (A and B) and put the sum in another matrix (C). This is what I tried. Any advice?
The error I get is
no match for 'operator[]' (operand types are 'Matrix' and 'int')
inline Matrix& operator+(Matrix& A, Matrix& B)
{
Matrix *C = new Matrix;
C->rows = A.rows;
C->columns = A.columns;
for(int i = 0; i < A.rows; i++)
for(int j = 0; j < A.columns; j++)
C[i][j] = A[i][j] + B[i][j];
}
return **C;
}
Add a operator '+' inside class like:
Matrix Matrix::operator+(const Matrix &other){
Matrix result = Matrix<T>(rows, other.columns);
if (this->rows == other.columns && this->columns == other.rows) {
for (int i = 0; i < this->rows; i++) {
for (int j = 0; j < this->columns; j++) {
result.n[i][j] = other.n[i][j] + this->n[i][j];
}
}
}
return result;
}
And the operator '=' to copy the result
Matrix& Matrix::operator=(const Matrix &other ){
if(this->columns<=other.columns && this->rows<=other.rows){
for(int i=0;i<this->rows;i++){
for(int j=0;j<this->columns;j++){
this->n[i][j]=other.n[i][j];
}
}
return (*this);
}else{
printf("ERROR");
}
}
Here's a basic Matrix implementation you could use.
Compatible with std::complex or whatever you own type is, as long as it's copy-constructible (see the main() in the link below).
template<class T>
struct Matrix {
std::vector<T> data;
size_t rows, cols;
Matrix(size_t rows_, size_t cols_, T value=T())
: data(rows_*cols_, value)
, rows(rows_)
, cols(cols_)
{
}
Matrix() = default;
Matrix(const Matrix& other) = default;
Matrix& operator=(const Matrix& other) = default;
Matrix(Matrix&& other) = default;
Matrix& operator=(Matrix&& other) = default;
T& operator()(size_t row, size_t col) {
return data.at(flatIndex(row, col));
}
const T& operator()(size_t row, size_t col) const {
return data.at(flatIndex(row, col));
}
Matrix operator+(const Matrix& other) const {
assert(data.size() == other.data.size());
assert(rows == other.rows);
assert(cols == other.cols);
Matrix sum = *this;
for (size_t i=0; i<data.size(); i++) {
sum.data.at(i) += other.data.at(i);
}
return sum;
}
protected:
size_t flatIndex(size_t row, size_t col) const {
return row * cols + col;
}
};
template<class T>
std::ostream& operator<<(std::ostream& os, const Matrix<T>& m) {
for (size_t r = 0; r<m.rows; r++) {
for (size_t c = 0; c<m.cols; c++) {
os << m(r, c) << " ";
}
os << '\n';
}
return os;
}
https://godbolt.org/z/Gvx5ac
If you really need performant/safe matrices, consider using a LinAlg library instead, like Eigen.
i have this class
class Matrix
{
int size;
std::unique_ptr<std::unique_ptr<int[]>[]> val;
public:
Matrix(int size1)
{
size=size1;
val=std::make_unique< std::unique_ptr<int[]>[] >(size);
...
}
... move constructor,move assignment operator
Matrix& operator+(Matrix &m)
{
Matrix sumMatrix(size);
for ( int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j){
sumMatrix.val[i][j]=this->val[i][j]+m.val[i][j];
}
}
return sumMatrix;
}
and main :
...
Matrix e=b+c;
std::cout<<"e="<<std::endl;
e.print();
and i have this error :
warning: reference to local variable 'sumMatrix' returned
[-Wreturn-local-addr]
Matrix sumMatrix(size);
Can someone please help me with this ??
Return by value, as you should for operator+ most of the time:
// vvv--Removed & vvvvv-----vvvvv--Const is more appropriate here
Matrix operator+(Matrix const &m) const { ... }
This will require a copy constructor, make sure to add that. Also note that you should probably collect your for-loop logic into an operator+= and simplify operator+ significantly while providing more functionality for the end-user:
Matrix& operator+=(Matrix const& m) {
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
//vvv--No need for this-> in C++
val[i][j] += m.val[i][j];
}
}
return *this;
}
Matrix operator+(Matrix const& m) const {
Matrix sumMatrix{m}; // requires a copy constructor.
sumMatrix += *this;
return sumMatrix;
}
CPP
#include "del2.h"
Matrix::Matrix()
{
dArray = NULL;
}
bool Matrix::isValid() const
{
if (dArray == NULL)
return false;
return true;
}
Matrix::~Matrix()
{
delete [] dArray;
}
Matrix::Matrix(unsigned int nRows)
{
rows = nRows;
columns = nRows;
dArray = new double[nRows * nRows];
for (unsigned int i = 0; i < nRows; i++)
{
for (unsigned int n = 0; n < nRows; n++)
{
at(i,n) = 0;
}
}
at(0,0) = 1;
at(rows-1,columns-1) = 1;
}
Matrix::Matrix(unsigned int nRows, unsigned int nColumns)
{
dArray = new double[nRows * nColumns];
rows = nRows;
columns = nColumns;
for (unsigned int i = 0; i < nRows; i++)
for (unsigned int n = 0; n < nColumns; n++)
dArray[i * columns + n] = 0;
}
const Matrix Matrix::operator =(const Matrix & rhs)
{
columns = rhs.getColumns();
rows = rhs.getRows();
delete [] dArray;
dArray = new double[rows * columns];
for (int row = 0; row < rows; row++)
for (int column = 0; column < columns; column++)
at(row,column) = rhs.at(row,column);
return *this;
}
std::ostream & operator <<( std::ostream & out, const Matrix & classPrint )
{
if (!classPrint.isValid())
return out;
int rows = classPrint.getRows();
int columns = classPrint.getColumns();
out << std::endl;
for (int i = 0; i < rows; i++)
{
out << "| ";
for (int n = 0; n < columns; n++)
out << classPrint.at(i,n) << " ";
out << "|" << std::endl;
}
out << endl;
return out;
}
HEADER:
#ifndef DEL2
#define DEL2
#include <iostream>
using namespace std;
class Matrix
{
private:
int rows;
int columns;
double * dArray;
public:
~Matrix();
Matrix();
explicit Matrix(unsigned int nRows);
Matrix(unsigned int nRows, unsigned int nColumns);
const Matrix operator =(const Matrix & rhs);
const double at(int row, int column) const
{ return dArray[ row*this->columns + column ]; }
double & at( int row, int column )
{ return dArray[ row*this->columns + column ]; }
const int getRows() const {return rows;}
const int getColumns() const {return columns;}
bool isValid() const;
};
std::ostream & operator <<( std::ostream & out, const Matrix & classPrint );
#endif // MATRIX
Main:
#include <iostream>
#include "del2.h"
using namespace std;
int main()
{
Matrix A;
Matrix B(10);
A = B;
cout << A;
return 0;
}
When I run this, the following happens:
The first index, matrix[0] of A, always becomes some weird number like 2.22323e-306. I don't understand why. Even when I try to set "at(0,0) = 1;" in the operator = - function after the loop, it still doesn't have 0.
The problem is here
const Matrix operator =(const Matrix & rhs);
should be
const Matrix& operator =(const Matrix & rhs);
and the definition should be
const Matrix& Matrix::operator =(const Matrix & rhs)
{
if (&rhs == this)
return *this;
Otherwwise operator= is returning a copy of the Matrix which will have dArray same as the original Matrix. Your data will be deleted when the temporary returned array goes out of scope.
Be carefull the operator = is not correct
Matrix & operator = (const Matrix & rhs){
if (&rhs != this){
// Your stuff here
}
return *this;
}
Calling delete [] on a null array is undefined. It can crash.
You must also define the copy constructor
I am struggling to get my method to work. I am a beginner in C++. I am trying to find a dot product of two vectors. I am getting a few errors in the for loops. How can I fix them?
float dot(Matrixf const& vec1, Matrixf const& vec2) {
// error check
if (!vec1.isVector() || !vec2.isVector()) {
throw std::runtime_error("Unable to do dot product: not column vectors.");
}
if (vec1.nrows() != vec2.nrows()) {
throw std::runtime_error("Unable to do dot product: vector lengths not equal.");
}
/** implementing dot product *************************************/
float ret = 0;
for(unsigned i = 0; i < vec1.ncols(); ++i){
for(unsigned j =0; j< vec2.nrows(); ++j){
ret += vec1[i] * vec2[j];
}
}
return ret;
}
Matrixf class
#include "matrixf.h"
#include <iostream>
Matrixf::Matrixf(unsigned int rows, unsigned int cols) {
rows_ = rows;
cols_ = cols;
data_ = new float[rows_ * cols_];
// set all initial values to zero
for (unsigned int r = 0; r < rows_; ++r) {
for (unsigned int c = 0; c < cols_; ++c) {
data_[r * cols_ + c] = 0;
}
}
}
Matrixf::~Matrixf() {
delete data_;
}
Matrixf::Matrixf(Matrixf const& other) {
rows_ = other.rows_;
cols_ = other.cols_;
data_ = new float[rows_ * cols_];
for (unsigned int i = 0; i < rows_ * cols_; ++i) {
data_[i] = other.data_[i];
}
}
Matrixf& Matrixf::operator=(Matrixf const& other) {
// handles self assignment
if (this == &other) {
return *this;
}
delete data_;
rows_ = other.rows_;
cols_ = other.cols_;
data_ = new float[rows_ * cols_];
for (unsigned int i = 0; i < rows_ * cols_; ++i) {
data_[i] = other.data_[i];
}
return *this;
}
float Matrixf::get(unsigned int row, unsigned int col) const {
#ifndef NDEBUG
if (row >= rows_ || col >= cols_) {
throw std::runtime_error("Matrix index out of bounds.");
}
#endif
return data_[row * cols_ + col];
}
void Matrixf::set(unsigned int row, unsigned int col, float val) {
#ifndef NDEBUG
if (row >= rows_ || col >= cols_) {
throw std::runtime_error("Matrix index out of bounds.");
}
#endif
data_[row * cols_ + col] = val;
}
float& Matrixf::operator()(unsigned int row, unsigned int col) {
return data_[row * cols_ + col];
}
float Matrixf::operator()(unsigned int row, unsigned int col) const {
return data_[row * cols_ + col];
}
unsigned int Matrixf::nrows() const {
return rows_;
}
unsigned int Matrixf::ncols() const {
return cols_;
}
bool Matrixf::isVector() const {
return (cols_ == 1);
}
Matrixf Matrixf::eye(unsigned int size) {
Matrixf e(size, size);
for (unsigned int i = 0; i < size; ++i) {
e.set(i, i, 1);
}
return e;
}
std::ostream& operator << (std::ostream& os, Matrixf const& matrix) {
for (unsigned int r = 0; r < matrix.nrows(); ++r) {
for (unsigned int c = 0; c < matrix.ncols(); ++c) {
os << matrix.data_[r * matrix.cols_ + c] << " ";
}
os << "\n";
}
return os;
}
I think you just want one loop:
for(unsigned i = 0; i < vec1.ncols(); ++i){
ret += vec1[i] * vec2[i];
}
I also notice that you compare
vec1.nrows() != vec2.nrows()
but you use ncols() in the loop. Which one do you want?
I see from your other question that you write a ray tracer.
In ray tracers, it is common and virtually always the case that you have separate data structures for vectors and matrices, because they are almost always used differently, and specializations in programming almost always lead to faster code.
If you then define your dot product for only vectors, the dot product code will become simple.
I'm implementing my own matrix class in c++ to help me develop my understanding of the language. I read somewhere that if you've got a working += operator, to use it in your + operator. So that's what I've got:
template <class T>
const Matrix<T>& Matrix<T>::operator+(const Matrix<T> &R){
Matrix<T> copy(*this);
return copy += R;
}
And here is the += operator overload:
template <class T>
const Matrix<T>& Matrix<T>::operator+=(const Matrix<T> & second_matrix){
//Learn how to throw errors....
if (rows != second_matrix.getNumRows() || cols != second_matrix.getNumCols()){throw "Dimension mismatch.";}
int i,j;
for (i = 0; i < rows; i++){
for (j = 0; j < cols; j++){
data[i][j] += second_matrix.get(i,j);
}
}
return *this;
}
I can use the += just fine (eg, a += b; returns no errors). But calling the + operator (eg, a = b + c;) returns :
test.cpp.out(77055) malloc: *** error for object 0x300000004: pointer being freed was not allocated
Just for completeness, here's my destructor:
template <class T>
Matrix<T>::~Matrix(){
for (int i = 1; i < rows; i++){
delete[] data[i]; }
delete[] data;
}
I've been using C++ for a couple years on and off, and still have trouble sometimes keeping track of pointers. I hope that's normal...
Any help would be great. Thanks!
EDIT: here's my copy constructor. It was set to free the data arrays but i removed that. now I get segmentation faults.
template <class T>
Matrix<T>::Matrix(const Matrix<T>& second_matrix){
rows = second_matrix.getNumRows();
cols = second_matrix.getNumCols();
data = new T*[rows];
int i,j;
for (i = 0; i < rows; i++){
data[i] = new T[cols];
}
for (i = 0; i < rows; i++){
for (j = 0; j < cols; j++){
data[i][j] = second_matrix.get(i,j);
}
}
}
operator+() should not return a reference type as it is a new (locally declared) instance that holds the result of the operation.
This is how I have implemented such operators for a Matrix class, this is based on a Vector Class. Once you define some operators all other should be defined in terms of the simplest operators:
Matrix::Matrix(const Matrix& rMatrix) :
_iRows(rMatrix._iRows), _iColumns(rMatrix._iColumns), _pVector(0)
{
_pVector = new Vector[_iRows];
for (int i = 0; i < _iRows; i++) { _pVector[i] = rMatrix._pVector[i]; }
}
Matrix& Matrix::operator=(const Matrix& rMatrix)
{
if (this != &rMatrix)
{
if (0 != _pVector) { delete[] _pVector; pVector = 0; }
_iRows = rMatrix._iRows;
_iColumns = rMatrix._iColumns;
_pVector = new Vector[_iRows];
for (int i = 0; i < _iRows; i++) { _pVector[i] = rMatrix._pVector[i]; }
}
return *this;
}
Matrix& Matrix::operator+=(const Matrix& rMatrix)
{
*this = *this + rMatrix;
return *this;
}
Matrix Matrix::operator+(const Matrix& rMatrix) const
{
Matrix matrix(_iRows, _iColumns);
ValidateSizes(rMatrix);
for (int i = 0; i < _iRows; i++) { matrix._pVector[i] = _pVector[i] + rMatrix._pVector[i]; }
return matrix;
}
Matrix operator+(const Matrix& rMatrix, double dNum)
{
Matrix matrix(rMatrix._iRows, rMatrix._iColumns);
matrix.ValidateSizes(rMatrix);
for (int i = 0; i < matrix._iRows; i++) { matrix._pVector[i] = dNum + rMatrix._pVector[i]; }
return matrix;
}
Matrix operator+(double dNum, const Matrix& rMatrix)
{
return operator+(rMatrix, dNum);
}
bool Matrix::ValidateSizes(const Matrix& rMatrix) const
{
if (_iRows != rMatrix._iRows) { /* THROW EXCEPTION */ }
if (_iColumns != rMatrix._iColumns) { /* THROW EXCEPTION */ }
return true;
}
If this a matrix for 3D rendering/simulation I would recommend NOT dynamically allocating the memory like that. You can end up with the memory being spread all over the place which causes caching issues. It also leads to potential memory bugs.
template <typename T>
class Matrix
{
public:
T m_Data[4][4];
};
or if you want something non-4x4
template <typename T, unsigned int rows, unsigned int columns>
class Matrix
{
public:
T m_Data[rows][columns];
};
and then dynamically allocate the Matrix objects.