I have the following problem:
I've a precomputed 2d matrix of values which i need to lookup very often and compute only once
The size of the matrix is about 4000x4000 at most
The matrix won't be sparse, i typically need almost all values.
The values in the matrix can be boolean, integer or double. At least they are always small objects
Currently i am storing the precomputed values in a std::vector<<std::vector<T>>, and i've noticed the lookups into this datastructure takes quite some time in heavy computations. I've googled around and so far the suggested implementation seems to be to try a solution in which all the memory is stored contigious using an 1D array where the location in this array is computed based on i and j.
Does anybody have a good example implementation of this or has an even better suggestion? I couldn't find a modern C++ example, while it seems to be a very common problem to me. I'd prefer to use someone elses code instead of reinventing the wheel here. Of course i will measure the differences to see whether it actually improves performance.
Examples i've found:
https://medium.com/#patdhlk/c-2d-array-a-different-better-solution-6d371363ebf8
https://secure.eld.leidenuniv.nl/~moene/Home/tips/matrix2d/
Here is a very simple and efficient 2-d matrix. The 'main' creates a 10000x10000 double array 'mat', then filled it with random number. The array 'mat' is copied into another array 'mat2'. your may input two integers 'n' and 'm' between 0 and 9999 to fetch the double data at mat2(n,m).
Feel free to use or test it. Let me know if you encounter problems or need some more functions to be implemented. Good luck!
#ifndef ytlu_simple_matrix_class_
#define ytlu_simple_matrix_class_
#include <iostream>
#include <iomanip>
#include <complex>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j];
} // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j)
{
ptr = new T [this->size] ;
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
~tMatrix() {delete [] this->ptr;}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix<std::complex<double> >;
#endif
//
//
#include <ctime>
#include <cstdlib>
#define N1 10000
int main()
{
int n, m;
std:srand(time(NULL)); // randomize
rMatrix mat(N1, N1); // declare a 10000 x 10000 double matrix
//
// fill the whole matrix with double random number 0.0 - 1.0
//
for (int i = 0; i<mat.row; i++)
{ for (int j=0; j<mat.col; j++) mat(i, j) = (double)std::rand() / (double)RAND_MAX; }
//
// copy mat to mat 2 just for test
//
rMatrix mat2 = mat;
//
// fetch data test input 0 <= n m < 10000 to print mat2(n, m)
//
while(1)
{
std::cout << "Fetch 2d array at (n m) = ";
std::cin >> n >> m;
if ((n < 0) || (m < 0) || (n > mat2.row) || (m > mat2.col) )break;
std::cout << "mat(" << n << ", " << m << ") = " << mat2(n, m) << std::endl << std::endl;
}
return 0;
}
The compile parameter I used and the test run. It takes a couple seconds to fill the random numbers, and I felt no lapse at all in fetch a data running in my aged PC.
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ g++ -O3 -s mtx_class.cpp -o a.exe
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ ./a.exe
Fetch 2d array at (n m) = 7000 9950
mat(7000, 9950) = 0.638447
Fetch 2d array at (n m) = 2904 5678
mat(2904, 5678) = 0.655934
Fetch 2d array at (n m) = -3 4
Related
I'm trying to do a Matrix class using C++ Vector, but i don't know why the inside of "Matrix result" inside my function isn't passed to my object but it remain enclosed inside the function.
for semplicity so far I've tryed only to do an "addition function" among two Matrices.
I have tryied to work with pointer but in this way (according to my knowledgs) i cant call my funtion to an object in this wise:
foo.function1(bar1).function2(bar2);
but working with pointer i have to call function in this manner:
foo.function1(bar1);
foo.function2(bar2);
//and so on..
this is my header file:
#include <iostream>
#include <vector>
using namespace std;
class Matrix
{
public:
Matrix (int height, int width);
Matrix add(Matrix m);
Matrix applyFunction(double (*function)(double));
void print();
private:
vector<vector<double> > matrix;
int height;
int width;
};
this is the .cpp file:
Matrix::Matrix(int height, int width)
{
this->height = height;
this->width = width;
this->matrix = vector<vector<double> >(this->height, vector<double>(this->width));
}
Matrix Matrix::add(Matrix m)
{
Matrix result(this->height, this->width);
if (m.height== this->height&& m.width== this->width)
{
for (int i = 0; i < this->height; i++)
{
for (int j = 0; j < this->width; j++)
{
result.matrix[i][j] = this->matrix[i][j] + m.matrix[i][j];
}
return result;
}
}
else
{
cout << "Impossible to do addition, matrices doesn't have the same dimension" << endl;
return result;
}
}
Matrix Matrix::applyFunction(double(*function)(double))
{
Matrix result(this->height, this->width);
for (int i = 0; i < this->height; i++)
{
for (int j = 0; j < this->width; j++)
{
result.matrix[i][j] = (*function)(this->matrix[i][j]);
}
}
return result;
}
void Matrix::print()
{
for (int i = 0; i < this->height; i++)
{
for (int j = 0; j < this->width; j++)
{
cout << this->matrix[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
the output should be the addition beetwen A B 2x2:
x1 x2
x3 x4
but computer show only zeros.
Your member functions all return a new object (they return "by value").
From your usage of chaining, it seems like you actually want to modify the object and return *this by reference.
Otherwise you'll need something like:
auto bar2 = foo.function1(bar1);
auto bar3 = foo.function2(bar2);
// etc
There are no pointers here at present.
There are two variants how you can implement your add
Matrix add(Matrix m)
{
// optimisation: you don't need separate result, m already IS a copy!
// so you can just calculate:
...
{
m.matrix[i][j] += this->matrix[i][j];
}
return m;
}
or:
Matrix& add(Matrix const& m)
// ^ accept const reference to avoid unnecessary copy
// ^ returning reference(!)
{
...
{
// modifies itself!
this->matrix[i][j] += m.matrix[i][j];
}
return *this; // <- (!)
}
This allows now to do:
Matrix m0, m1, m2;
m0.add(m1).add(m2);
// m0 now contains the result, original value is lost (!)
So you don't need the final assignment as in first variant:
m0 = m0.add(m1).add(m2);
// or assign to a new variable, if you want to retain m0's original values
which is what you lacked in your question (thus you did not get the desired result).
Maybe you want to have both variants, and you might rename one of. But there's a nice feature in C++ that you might like even better: Operator overloading. Consider ordinary int:
int n0, n1;
n0 += n1;
int n2 = n0 + n1;
Well, suppose you know what's going on. And if you could do exactly the same with your matrices? Actually, you can! You need to do is overloading the operators:
Matrix& operator+=(Matrix const& m)
{
// identical to second variant of add above!
}
Matrix operator+(Matrix m) // again: the copy!
{
// now implement in terms of operator+=:
return m += *this;
}
Yes, now you can do:
Matrix m0, m1, m2;
m0 += m1 += m2;
m2 = m1 + m0;
Alternatively (and I'd prefer it) you can implement the second operator (operator+) as free standing function as well:
// defined OUTSIDE Matrix class!
Matrix operator+(Matrix first, Matrix const& second)
{
return first += second;
}
Finally: If dimensions don't match, better than returning some dummy matrix would be throwing some exception; std::domain_error might be a candidate for, or you define your own exception, something like SizeMismatch. And please don't output anything to console or elsewhere in such operators, this is not what anybody would expect from them, additionally, you impose console output to others who might consider it inappropriate (perhaps they want output in another language?).
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<int> v(100); // defined a vector of size 100
for(i=1;i<=50;i++) {
v[i]=i; // storing the values as we do in 1-d array
}
for(int i=1;i<=50;i++) {
cout<<"index="<<i<<" "<<v[i]<<"\n"; // It will give output similar
// to 1-d array
}
return 0;
}
So this is the case of one dimensional vector where index of vector is integer and the value is also integer. The above code is running fine.
But i want to take the index of a vector as pair (i,j) and the value as an integer.
See the below code for more clarification .
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<pair<int,int>> ve(make_pair(100,100));
//defined a vector of size of indices (100,100)
for(i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
ve[make_pair(i,j)]=2; // Storing value of 2 in all the
// (i,j) indices
}
}
for(int i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
cout<<ve[make_pair(i,j)]<<" ";
// Output should be 2 in all the possible pairs of (i,j)
}
}
return 0;
}
But the above code is not working :(.
Please tell me how i can fix this problem.
Vectors, like arrays, work only with integer indexes. For a vector vec, the index must be in range 0 <= index < vec.size(), otherwise it either does not compile (not convertible to unsigned int) or the behavior is undefined (out of bounds).
You have written
vector<pair<int,int>> ve
Which means that you create a vector that contains pairs, not that it is indexed by pairs.
Now, if you want a two dimensional vector, i.e. a matrix, you should check Boost matrix. You can also implement it yourself, but making it general purpose will take some effort. The basic idea is to convert the pair to an single integer value. The simplest implementation is:
template <class T>
void init_2d(std::vector<T> &vec, std::pair<unsigned, unsigned> coordinates)
{
vec.resize(coordinates.first * coordinates.second);
}
inline unsigned flatten(std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return coordinates.first * num_columns + coordinates.second;
}
template <class T>
T & get_2d(std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
template <class T>
const T & get_2d(const std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
and then use it in your code:
int main() {
std::vector<int> ve;
auto dimensions = std::make_pair(100,100);
init_2d(ve, dimensions);
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
get_2d(ve, {i,j}, dimensions.second) =j;
}
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
std::cout << get_2d(ve, {i,j}, dimensions.second) <<" ";
std::cout << '\n';
}
return 0;
}
But, instead of reimplementing existing code, you should prefer to use boost matrix. If you are trying to learn how a matrix can be implemented (which is a very good idea), then go on and try to convert the above functions+vector into a class, and put the dimensions pair into that class. Having a class, for a matrix, is better than to use separate functions. It is easier to maintain invariants for a class than for separate functions.
Note: you can use std::map<std::pair<int, int>> instead, but it will be more difficult to iterate over it and it will be much slower. If it makes your code clearer, using std::map is a good idea, but it is not clear cut whether std::map<pair<...>> is easier to work with than with std::vector + _2d functions.
I would suggest you to use map instead.
Operator [] for map takes key_type as parameter which is a container which means you can use pair object as index (called key in map), however Operator [] for vetor takes size_type as parameter which is an unsigned integer.
Your code could look like the following:
map< pair<int, int>, int > notVector;
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
notVector[make_pair(i,j)]=2; // Storing value of 2 in all the (i,j) indices
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
cout<<notVector[make_pair(i,j)]<<" ";
another solution: create your own container by aggregating a standard one.
Extremely simplified example:
#include <vector>
#include <iostream>
struct xy
{
std::size_t x, y;
};
constexpr std::size_t linear_extent(xy _)
{
return _.y * _.x;
}
constexpr std::size_t linear_position(xy _, xy extent)
{
return _.y * extent.x + _.x;
}
template<class T>
struct vector_2d
{
vector_2d(xy size, T x = T())
: extent_(size)
, storage_(linear_extent(extent_), x)
{
}
T& operator[](xy const& _)
{
return storage_[linear_position(_, extent_)];
}
T const& operator[](xy const& _) const
{
return storage_[linear_position(_, extent_)];
}
constexpr auto extent() const { return extent_; }
xy extent_;
std::vector<T> storage_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, vector_2d<T> const& v)
{
const char* sep = " [";
os << "[";
auto extent = v.extent();
for(auto y = std::size_t(0) ; y < extent.y ; ++y)
{
os << sep;
const char* sep2 = " ";
for (auto x = size_t(0) ; x < extent.x ; ++x)
{
std::cout << sep2 << v[{x, y}];
sep2 = ", ";
}
os << " ]";
sep = "\n [";
}
os << " ]";
return os;
}
int main()
{
auto v = vector_2d<int>({5, 5});
v[{1, 3}] = 8;
std::cout << v << std::endl;
}
Keep it simple
All you need is 1 (One!) C++ line: ...+ Update: Optional macro (the macro is to answer #eneski comment):
std::vector<std::vector<int>> ve(100, std::vector<int>(100, 0)); // Initialize to 0
// Turns [wr(pair)] syntax to [pair.first][pair.second] syntax:
#define wr(pr) (pr).first][(pr).second // Wrapper macro
And than use:
ve[wr(std::make_pair(i, j))] = 35; // For example
int val = ve[wr(std::make_pair(i, j))];
// Or:
ve[i][j] = 70; // For example
val = ve[i][j];
There is no real need to use the wr wrapper macro. Use ve[i][j] and if you have somewhere in your code a std::pair p, use: ve[p.first][p.second] instead of ve[p] - Both are the same. Also, it is nonsense to take (i, j) and to make_pair on-the-fly just to use them again as [i][j] indexes. If, despite all, one insists on the syntax, than use the wr wrapper macro.
--
But, in a case of a fixed sequential range, a 2D std::array is a better choice (& you can add the wrapper macro as well, if you insist):
#include <array>
int main()
{
int i = 7, j = 5;
std::array<std::array<int, 100>, 100> ar; // 100 X 100
ar[0].fill(0); ar.fill(ar[0]); // Initialize to 0
ar[i][j] = 35; // For example
return 0;
}
Are you simply attempting to access 1d vector content as if it was a 2d vector? Perhaps you could use a helper function to convert 2d index into 1d index, for example:
#include <vector>
#include <iostream>
#include <cassert>
template<size_t ROWS, size_t COLS>
size_t convertIndex(size_t row, size_t col)
{
assert(row < ROWS && col < COLS);
return row * COLS + col;
}
int main()
{
std::vector<int> v =
{
0,1,2,3,4,
5,6,7,8,9
};
std::cout << v[convertIndex<2, 5>(1, 3)];
}
This outputs 8
#include <iostream>
using namespace std;
int main() {
int n,d,i=0,temp;
cin>>n>>d;
int a[1000000];
for(i=0;i<n;i++){
cin>>a[i];
}
while(d--){
temp=a[0];
for(i=1;i<n;i++){
a[i-1]=a[i];}
a[n-1]=temp;
}
for(i=0;i<n;i++){
cout<<a[i]<<" ";
}
return 0;
}
how to optimize it further as it's giving TLE error. the input file is very large obviously.
Some suggestions:
Rotate by the full amount d in a single loop (note that the result is a different array b):
for (i = 0; i < n; i++) {
b[(i+n-d) % n]=a[i];
}
Don't touch the array at all but transform the index when accessing it, for example:
cout << a[(i+n-d) % n] << " ";
The second version requires extra calculation to be done whenever accessing an array element but it should be faster if you don't need to access all array elements after each rotate operation.
There is also a way to do the rotation in-place by using a helper function that reverses a range of the array. It's a bit odd but might be the best solution. For convenience I have used a std::vector instead of an array here:
void ReverseVector( std::vector<int>& a, int from, int to ) {
for (auto i = 0; i < (to - from) / 2; i++) {
auto tmp = a[from + i];
a[from + i] = a[to - i];
a[to-i] = tmp;
}
}
void RotateVector( std::vector<int>& a, int distance ) {
distance = (distance + a.size()) % a.size();
ReverseVector( a, 0, a.size() - 1 );
ReverseVector( a, 0, distance - 1 );
ReverseVector( a, distance, a.size() - 1 );
}
I'm trying to create a template to allocate dynamically an 2D matrix.
Usually what I do is:
float **Allocate_matrix_float (int m, int n)
{
float **v;
int i;
if (m < 1 || n < 1) {
printf ("** Invalid parameter **\n");
return (NULL);
}
v = (float **) calloc (m, sizeof(float *));
if (v == NULL) {
printf ("** Unsufficient memory **");
return (NULL);
}
for ( i = 0; i < m; i++ ) {
v[i] = (float*) calloc (n, sizeof(float));
if (v[i] == NULL) {
printf ("** Unsufficient memory **");
return (NULL);
}
}
return (v);
}
float **free_matrix_float (int m, int n, float **v)
{
int i;
if (v == NULL) return (NULL);
if (m < 1 || n < 1) {
printf ("** invalid parameter**\n");
return (v);
}
for (i=0; i<m; i++) free (v[i]);
free (v);
return (NULL);
}
However I'd like to create a template to allocate any type of 2D matrix. Can anyone help me?
The ideal would be something like:
template<typename T>
T**Allocate_matrix(int n, int m)
...
All of your allocation and deallocation code can be replaced by
std::vector<std::vector<float>> matrix(m, std::vector(n));
Seriously. It even deallocates itself when it goes out of scope, so you have almost no memory management issues.
#include <iostream>
#include <vector>
int main()
{
size_t m;
size_t n;
std::cin >> m >> n;
// floats initialized to 0.0
std::vector<std::vector<float>> fltmatrix(m, std::vector<float>(n));
// doubles initialized to 0.0
std::vector<std::vector<double>> dblmatrix(m, std::vector<double>(n));
// bools initialized to true
std::vector<std::vector<bool>> boolmatrix(m, std::vector<bool>(n), true);
// ints initialized to 42
std::vector<std::vector<int>> intmatrix(m, std::vector<int>(n, 42));
} <-- all vectors are released here.
Practically no effort required.
However, because each vector is it's own independent entity and you have m+1 vectors, you have m+1 different places in memory that your program needs to look to return a value. This can have a really bad impact on your programs performance as small matrices, say a 3x3, can't take full advantage of the CPU's caching and this can be very, very noticeable when crunching large numbers of matrices. If you don't care, stop reading and go with the simple vector of vector approach.
If you do care, wrap a 1D vector in a class:
#include <iostream>
#include <vector>
template<class TYPE>
class Matrix
{
private:
size_t rows, columns;
std::vector<TYPE> matrix;
public:
Matrix(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), matrix(rows * columns)
{
}
Matrix(size_t numrows, size_t numcols, TYPE init) :
rows(numrows), columns(numcols), matrix(rows * columns, init)
{
}
TYPE & operator()(size_t row, size_t column)
{
// check bounds here
return matrix[row * columns + column];
}
TYPE operator()(size_t row, size_t column) const
{
// check bounds here
return matrix[row * columns + column];
}
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
friend std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
for (int i = 0; i < in.getRows(); i++)
{
for (int j = 0; j < in.getColumns(); j++)
{
out << in(i, j) << ' ';
}
out << std::endl;
}
return out;
}
};
int main()
{
size_t m;
size_t n;
std::cin >> m >> n;
// floats initialized to 0.0
Matrix<float> fltmatrix(m, n);
std::cout << fltmatrix << std::endl;
// doubles initialized to 0.0
Matrix<double> dblmatrix(m, n);
std::cout << dblmatrix << std::endl;
// bools initialized to true
Matrix<bool> boolmatrix(m, n, true);
std::cout << boolmatrix << std::endl;
// ints initialized to 42
Matrix<int> intmatrix(m, n, 42);
std::cout << intmatrix << std::endl;
}
More effort, but should be faster. Profile your program to see if Matrix is right for you.
operator<< is included as an output convenience and as an example of how to access Matrix's cells.
And if you just have to use an array... Things get a lot uglier. For one thing, you will have to be Rule of Three (and possibly Rule of Five) compliant and pick up a bunch of extra functions that, frankly, you're probably not going to get right the first few times.
I'm not even sure I can get it right if I just bang one out, and I have a perfectly good alternative, so I'm not going to. What you can gain is a matrix that does not spend time initializing the matrix before use. If that is an issue (profile, profile, profile!) I'd call that a new question. The current question uses calloc so it doesn't look like OP is concerned.
As paddy mentions here using vector-of-vector is not practical, difficult to change and suffers from cache misses. As well as using bare pointers is impractical in terms of C++ which provides better tools like operator overloading.
Taking paddy's implementation as basis your 2d matrix can be implemented in the following way:
template <class T>
class SimpleMatrix
{
public:
SimpleMatrix( int rows, int cols, const T& initVal = T() )
: m_data( rows * cols, initVal )
, m_rows( rows )
, m_cols( cols )
{
}
// Direct vector access and indexing
operator const vector<T>& () const { return m_data; }
int Index( int row, int col ) const { return row * m_cols + col; }
// Get a single value
T & Value( int row, int col ) { return m_data[Index(row,col)]; }
const T & Value( int row, int col ) const { return m_data[Index(row,col)]; }
// Proxy structure to allow [][] indexing
struct Proxy
{
private:
friend class SimpleMatrix<T>;
SimpleMatrix<T>* m_matrix;
int m_row;
Proxy( SimpleMatrix<T>* m, int row ) : m_matrix(m), m_row(row) {}
public:
T & operator[] ( int col ) { return m_matrix->Value(m_row, col); }
const T & operator[] ( int col ) const { return m_matrix->Value(m_row, col); }
};
Proxy operator[]( int row ) { return Proxy(this, row); }
const Proxy operator[]( int row ) const { return Proxy(const_cast<SimpleMatrix<T>*>(this), row); }
private:
vector<T> m_data;
int m_rows;
int m_cols;
};
And use it in the following way:
SimpleMatrix<int> m(10, 2);
const SimpleMatrix<int>& cm = m;
m[1][1] = 1;
cout << cm[1][1];
This will also allow you to check the boundaries of the index.
I am trying to get an understanding of how to work with matrices in C++. The code at the bottom is supposed to take an input matrix and return the places where there are 0s. However, I am getting the following errors:
matrix.cpp:47:3: error: no matching function for call to 'make_zero' make_zero(i,j,l);
^~~~~~~~~
matrix.cpp:8:6: note: candidate function not viable: no known conversion from 'double [i][j]' to
'double (*)[col]' for 3rd argument
void make_zero(int row, int col, double matrix[row][col])
^
1 error generated.
when I try to run the following code:
// Matrix
#include <iostream>
#include <stdio.h>
using namespace std;
void make_zero(int row, int col, double matrix[row][col])
{
int k,l;
for(k=0;k<row;k++)
for(l=0;l<col;l++)
{
if(matrix[k][l]==0)
printf("%d %d\n",k,l);
}
}
int main ()
{
int i = 0,j = 0;
cout << "Enter no of rows of the matrix";
cin >> i;
cout << "Enter no of columns of the matrix";
cin >> j;
double l[i][j];
int p = 0, q = 0;
while (p < i) {
while (q < j) {
cout << "Enter the" << p + 1 << "*" << q + 1 << "entry";
cin >> l[p][q];
q = q + 1;
}
p = p + 1;
q = 0;
}
cout << l << "\n";
make_zero(i,j,l);
}
Any help would be appreciated. Thanks.
There are a bunch of ways to do this with pointers. The most common is
void make_zero(int row, int col, double ** matrix)
defines a pointer (usually rows) to a pointer (usually columns). Unfortunately
double l[i][j];
does not define a pointer to a pointer. If this syntax is supported by the compiler, and the compiler is not required to allow arrays of variable length, it most likely defines a pointer to a 1D array (double l[i*j];) and hides the indexing arithmetic used to convert the array to two dimensions. Anyway, it can't be passed to a double ** because it isn't a double **
Trying to pass as an array is troublesome
void make_zero(int row, int col, double matrix[][NUMBER_OF_COLUMNS])
The number of columns in the array must be known to perform the indexing arithmetic and be provided to any functions called with it. This means that number of columns cannot be changed at run time because the indexing used by the function will be rendered invalid.
Getting around this would require changes to the compiler that will drive it further and further from the C++ standard. A bad idea since there are a number of simple ways around calling functions with multi dimensional arrays. Most depend on arrays of arrays or std::vectors of std::vectors.
And when it comes to these solutions, as far as I'm concerned, the best is don't. I'm not going to cover them.
None of the arrays representing a dimension are guaranteed to be anywhere close to the others in memory, and this limits the CPU's ability to read and cache. Without caching and being able to look ahead, a modern CPU is at a serious performance disadvantage. (Read for more information: Why is it faster to process a sorted array than an unsorted array?)
So what you want is a 1 D array, and those are easy to pass around. The indexing math is also easy, row number * size of column + column number, but you need to pass at least the size of the column around. Rather than scatter the book-keeping around like this:
void make_zero(int row, int col, std::vector<double> matrix)
make a wrapper class like this:
class Matrix
{
private:
std::vector<double> myArray;
size_t nrRows;
size_t nrColumns;
public:
Matrix(size_t rows, size_t columns) :
myArray(rows * columns), // allocate vector to store matrix.
nrRows(rows),
nrColumns(columns)
{
}
size_t getNrRows() const
{
return nrRows;
}
size_t getNrColumns() const
{
return nrColumns;
}
// gets value at row, column and returns a reference so caller can
// modify the value
double& operator()(size_t row, size_t column)
{
// note: No sanity check for row >= nrRows or column > nrColumns
return myArray[row * nrColumns + column];
}
// gets value at row, column and returns a copy so caller cannot
// change the contents of the Matrix
double operator()(size_t row, size_t column) const
{
return myArray[row * nrColumns + column];
}
};
Using the vector gets around a number of common pointer-to-array problems by managing its own memory. No destructor is required and Matrix can be copied and moved without requiring special handling because vector performs all that heavy lifting for us.
And as a usage example, let's make a function that prints the matrix out:
std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
for (size_t i = 0; i < in.getNrRows(); i++)
{
for (size_t j = 0; j < in.getNrColumns(); j++)
{
out << in(i,j) << ' ';
}
out << "\n";
}
return out;
}
And modifying OP's main function to use Matrix we get:
int main()
{
int i = 0, j = 0;
cout << "Enter no of rows of the matrix";
cin >> i;
cout << "Enter no of columns of the matrix";
cin >> j;
Matrix matrix(i,j);
int p = 0, q = 0;
while (p < i)
{
while (q < j)
{
cout << "Enter the" << p + 1 << "*" << q + 1 << "entry";
cin >> matrix(p,q);
q = q + 1;
}
p = p + 1;
q = 0;
}
cout << matrix << "\n";
make_zero(matrix);
}
void make_zero(int row, int col, double ** matrix)
Note, that you need to pass also size of the matrix separately.
Also you can use
std::vector<std::vector<double> >
instead and pass this object by reference, pointer, or just make a copy.
Actually, it works, but your problem in this line also:
double l[i][j];
i, j is unknown during the compile time.
You have 2 ways.
1) dynamically allocate the memory
2) use std::vector<std::vector<double> >. Default constructor already sets zero values. But you can do it manually like this:
#include <iostream>
#include <vector>
void make_zero(std::vector<std::vector<double> > & to_zero) {
for (int i = 0; i < to_zero.size(); ++i) {
for (int j = 0; j < to_zero[i].size(); ++j) {
to_zero[i][j] = 0;
}
}
}
void print_double_vector(const std::vector<std::vector<double> > & to_print) {
for (int i = 0; i < to_print.size(); ++i) {
for (int j = 0; j < to_print[i].size(); ++j) {
std::cout << to_print[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int main() {
// your code goes here
int n, m;
std::cin >> n >> m;
std::vector<std::vector<double> > d(n, std::vector<double>(m));
print_double_vector(d);
make_zero(d);
print_double_vector(d);
return 0;
}
http://ideone.com/0X53Yj