General nxn Matrix multiplication (also can be non-square)

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
4
down vote

favorite












This is a simple c++ code with a function mult to multiply matrices. This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.



The multiplication is done by iterating over the rows, and iterating (nested in the rows iteration) over the columns. While inside the columns iteration, the multiplication is performed, which is a dot product (again using a new iteration).



The simple demo shows the multiplication of A*A.



I wonder if there are better ways in writing this.



Code :



#include <iostream>
#include <string>

using namespace std;

int mult(int A[4][4], int B[4][4])

int C[4][4], num;

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
num = 0;
for(int k=0; k<4; k++)
num += A[i][k]*B[k][j];

C[i][j]=num;
cout << num << " ";

cout << endl;


return 0;



int main()

int A[4][4], ind=0;
cout << "Default Matrix A: n n";

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
A[i][j]=ind; ind++;
cout<< A[i][j]<< " ";

cout << endl;



cout << "nMultiplication of A^2: n n";
mult(A,A);
return 0;




Output :



Default Matrix A:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

Multiplication of A^2:

56 62 68 74
152 174 196 218
248 286 324 362
344 398 452 506






share|improve this question

















  • 2




    I think that implementing good mathematical libraries takes a lot of effort, unless your goal is to learn about that, I think the best way to go is to use a external library such as Eigen.
    – WooWapDaBug
    Feb 5 at 7:39











  • @WooWapDaBug thanks for the ref.. yes i prefer using creative algorithm.
    – Arief
    Feb 5 at 15:52
















up vote
4
down vote

favorite












This is a simple c++ code with a function mult to multiply matrices. This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.



The multiplication is done by iterating over the rows, and iterating (nested in the rows iteration) over the columns. While inside the columns iteration, the multiplication is performed, which is a dot product (again using a new iteration).



The simple demo shows the multiplication of A*A.



I wonder if there are better ways in writing this.



Code :



#include <iostream>
#include <string>

using namespace std;

int mult(int A[4][4], int B[4][4])

int C[4][4], num;

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
num = 0;
for(int k=0; k<4; k++)
num += A[i][k]*B[k][j];

C[i][j]=num;
cout << num << " ";

cout << endl;


return 0;



int main()

int A[4][4], ind=0;
cout << "Default Matrix A: n n";

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
A[i][j]=ind; ind++;
cout<< A[i][j]<< " ";

cout << endl;



cout << "nMultiplication of A^2: n n";
mult(A,A);
return 0;




Output :



Default Matrix A:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

Multiplication of A^2:

56 62 68 74
152 174 196 218
248 286 324 362
344 398 452 506






share|improve this question

















  • 2




    I think that implementing good mathematical libraries takes a lot of effort, unless your goal is to learn about that, I think the best way to go is to use a external library such as Eigen.
    – WooWapDaBug
    Feb 5 at 7:39











  • @WooWapDaBug thanks for the ref.. yes i prefer using creative algorithm.
    – Arief
    Feb 5 at 15:52












up vote
4
down vote

favorite









up vote
4
down vote

favorite











This is a simple c++ code with a function mult to multiply matrices. This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.



The multiplication is done by iterating over the rows, and iterating (nested in the rows iteration) over the columns. While inside the columns iteration, the multiplication is performed, which is a dot product (again using a new iteration).



The simple demo shows the multiplication of A*A.



I wonder if there are better ways in writing this.



Code :



#include <iostream>
#include <string>

using namespace std;

int mult(int A[4][4], int B[4][4])

int C[4][4], num;

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
num = 0;
for(int k=0; k<4; k++)
num += A[i][k]*B[k][j];

C[i][j]=num;
cout << num << " ";

cout << endl;


return 0;



int main()

int A[4][4], ind=0;
cout << "Default Matrix A: n n";

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
A[i][j]=ind; ind++;
cout<< A[i][j]<< " ";

cout << endl;



cout << "nMultiplication of A^2: n n";
mult(A,A);
return 0;




Output :



Default Matrix A:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

Multiplication of A^2:

56 62 68 74
152 174 196 218
248 286 324 362
344 398 452 506






share|improve this question













This is a simple c++ code with a function mult to multiply matrices. This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.



The multiplication is done by iterating over the rows, and iterating (nested in the rows iteration) over the columns. While inside the columns iteration, the multiplication is performed, which is a dot product (again using a new iteration).



The simple demo shows the multiplication of A*A.



I wonder if there are better ways in writing this.



Code :



#include <iostream>
#include <string>

using namespace std;

int mult(int A[4][4], int B[4][4])

int C[4][4], num;

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
num = 0;
for(int k=0; k<4; k++)
num += A[i][k]*B[k][j];

C[i][j]=num;
cout << num << " ";

cout << endl;


return 0;



int main()

int A[4][4], ind=0;
cout << "Default Matrix A: n n";

for (int i=0; i<4; i++)
for(int j=0; j<4; j++)
A[i][j]=ind; ind++;
cout<< A[i][j]<< " ";

cout << endl;



cout << "nMultiplication of A^2: n n";
mult(A,A);
return 0;




Output :



Default Matrix A:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

Multiplication of A^2:

56 62 68 74
152 174 196 218
248 286 324 362
344 398 452 506








share|improve this question












share|improve this question




share|improve this question








edited Feb 5 at 17:24
























asked Feb 4 at 23:13









Arief

420112




420112







  • 2




    I think that implementing good mathematical libraries takes a lot of effort, unless your goal is to learn about that, I think the best way to go is to use a external library such as Eigen.
    – WooWapDaBug
    Feb 5 at 7:39











  • @WooWapDaBug thanks for the ref.. yes i prefer using creative algorithm.
    – Arief
    Feb 5 at 15:52












  • 2




    I think that implementing good mathematical libraries takes a lot of effort, unless your goal is to learn about that, I think the best way to go is to use a external library such as Eigen.
    – WooWapDaBug
    Feb 5 at 7:39











  • @WooWapDaBug thanks for the ref.. yes i prefer using creative algorithm.
    – Arief
    Feb 5 at 15:52







2




2




I think that implementing good mathematical libraries takes a lot of effort, unless your goal is to learn about that, I think the best way to go is to use a external library such as Eigen.
– WooWapDaBug
Feb 5 at 7:39





I think that implementing good mathematical libraries takes a lot of effort, unless your goal is to learn about that, I think the best way to go is to use a external library such as Eigen.
– WooWapDaBug
Feb 5 at 7:39













@WooWapDaBug thanks for the ref.. yes i prefer using creative algorithm.
– Arief
Feb 5 at 15:52




@WooWapDaBug thanks for the ref.. yes i prefer using creative algorithm.
– Arief
Feb 5 at 15:52










1 Answer
1






active

oldest

votes

















up vote
3
down vote



accepted










Avoid using namespace std



This can cause name collisions because it adds every name in the std namespace to the global namespace. For a small program like this one it's unlikely that you'll run into any problems (then again, maybe not) but it's best to get into the habit of using the std:: prefix on names in the std namespace.



Alternatively, you can introduce using declarations like using std::cout; to add specific names to the global namespace.



Avoid std::endl in favor of n



std::endl flushes the stream, which can cause a loss in performance.



Declare variables in the most local scope possible



You declare num at the beginning of mult() but you don't actually use it (and initialize it to 0) until you're inside the j loop. It's better to simply declare and initialize it in the same place and in the place where you start to use it.



I would also rename it to be more descriptive (e.g. sum or dot_product).



Avoid hard-coded numbers



Your code works with $4times 4$ matrices but you've got 4 hard-coded all over the place. You say




This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.




But there are a lot of instances where 4 needs to be replaced. At the very minimum you should define 4 as a constant and use that constant in the code:



const std::size_t N = 4; // or constexpr instead of const if your compiler supports it

int mult(int A[N][N], int B[N][N])
int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;



Now I just need to change the definition of N once to use a number other than 4.



Use static_assert to enforce the condition that $N > 1$



If your compiler supports static_assert you can ensure that $N > 1$ at compile time and cause a compilation failure with a simple message to explain the problem.



Function template



The multiplication algorithm is basically the same for any $N > 1$, so this function is a good candidate for a function template based on the dimension $N$. For example, you have A with N = 4, but in the same program you could have a matrix (2D array) D with N = 3 and the same code is used to multiply with both matrices. Here's a demo using a function template:



#include <iostream>
#include <string>

template<std::size_t N>
int mult(int A[N][N], int B[N][N])
static_assert(N > 1, "N must be greater than 1");

int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
const std::size_t N = 4;
int A[N][N];
int ind = 0;
std::cout << "Default Matrix A: n n";

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
A[i][j] = ind; ind++;
std::cout << A[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of A^2: n n";
mult<N>(A, A);

const std::size_t N2 = 3;
int D[N2][N2];
ind = 0;
std::cout << "nDefault Matrix D: n n";

for (int i = 0; i < N2; i++)
for (int j = 0; j < N2; j++)
D[i][j] = ind; ind++;
std::cout << D[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of D^2: n n";
mult<N2>(D, D);
return 0;



Consider a Matrix class instead of 2D arrays



Mathematical libraries implement matrices as a class. Internally, the Matrix class may use 2D arrays to store the data, but client code shouldn't depend on how that data is stored. A Matrix class can hide the implementation details from client code.



Extend to non-square matrices



In general, an $N times M$ matrix $A$ can be multiplied with a matrix $B$ if $B$ is $M times P$ ($A$ has $M$ columns and $B$ has $M$ rows, but otherwise the two matrices can have different dimensions). With a function template you can easily extend the multiplication function to support non-square matrices. Simply add the necessary template arguments and tweak the algorithm to use dimensions other than N. Here's a demo:



#include <iostream>
#include <string>

template<std::size_t N, std::size_t M, std::size_t P>
int mult(int A[N][M], int B[M][P])
static_assert(N > 1, "N must be greater than 1");
static_assert(M > 1, "M must be greater than 1");
static_assert(P > 1, "P must be greater than 1");

int C[N][P];

for (int n = 0; n < N; n++)
for (int p = 0; p < P; p++)
int num = 0;
for (int m = 0; m < M; m++)
num += A[n][m] * B[m][p];

C[n][p] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
int A[4][3]
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12
;

int B[3][2]
1, 2,
3, 4,
5, 6
;

mult<4, 3, 2>(A, B);
return 0;



The demo program outputs the $N times P$ ($4 times 2$) matrix product:



22 28
49 64
76 100
103 136





share|improve this answer























  • Thanks. But currently, in CppDroid, none of your code succeed in compilation..
    – Arief
    Feb 5 at 17:48










  • @Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
    – Null
    Feb 5 at 17:55










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186770%2fgeneral-nxn-matrix-multiplication-also-can-be-non-square%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote



accepted










Avoid using namespace std



This can cause name collisions because it adds every name in the std namespace to the global namespace. For a small program like this one it's unlikely that you'll run into any problems (then again, maybe not) but it's best to get into the habit of using the std:: prefix on names in the std namespace.



Alternatively, you can introduce using declarations like using std::cout; to add specific names to the global namespace.



Avoid std::endl in favor of n



std::endl flushes the stream, which can cause a loss in performance.



Declare variables in the most local scope possible



You declare num at the beginning of mult() but you don't actually use it (and initialize it to 0) until you're inside the j loop. It's better to simply declare and initialize it in the same place and in the place where you start to use it.



I would also rename it to be more descriptive (e.g. sum or dot_product).



Avoid hard-coded numbers



Your code works with $4times 4$ matrices but you've got 4 hard-coded all over the place. You say




This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.




But there are a lot of instances where 4 needs to be replaced. At the very minimum you should define 4 as a constant and use that constant in the code:



const std::size_t N = 4; // or constexpr instead of const if your compiler supports it

int mult(int A[N][N], int B[N][N])
int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;



Now I just need to change the definition of N once to use a number other than 4.



Use static_assert to enforce the condition that $N > 1$



If your compiler supports static_assert you can ensure that $N > 1$ at compile time and cause a compilation failure with a simple message to explain the problem.



Function template



The multiplication algorithm is basically the same for any $N > 1$, so this function is a good candidate for a function template based on the dimension $N$. For example, you have A with N = 4, but in the same program you could have a matrix (2D array) D with N = 3 and the same code is used to multiply with both matrices. Here's a demo using a function template:



#include <iostream>
#include <string>

template<std::size_t N>
int mult(int A[N][N], int B[N][N])
static_assert(N > 1, "N must be greater than 1");

int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
const std::size_t N = 4;
int A[N][N];
int ind = 0;
std::cout << "Default Matrix A: n n";

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
A[i][j] = ind; ind++;
std::cout << A[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of A^2: n n";
mult<N>(A, A);

const std::size_t N2 = 3;
int D[N2][N2];
ind = 0;
std::cout << "nDefault Matrix D: n n";

for (int i = 0; i < N2; i++)
for (int j = 0; j < N2; j++)
D[i][j] = ind; ind++;
std::cout << D[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of D^2: n n";
mult<N2>(D, D);
return 0;



Consider a Matrix class instead of 2D arrays



Mathematical libraries implement matrices as a class. Internally, the Matrix class may use 2D arrays to store the data, but client code shouldn't depend on how that data is stored. A Matrix class can hide the implementation details from client code.



Extend to non-square matrices



In general, an $N times M$ matrix $A$ can be multiplied with a matrix $B$ if $B$ is $M times P$ ($A$ has $M$ columns and $B$ has $M$ rows, but otherwise the two matrices can have different dimensions). With a function template you can easily extend the multiplication function to support non-square matrices. Simply add the necessary template arguments and tweak the algorithm to use dimensions other than N. Here's a demo:



#include <iostream>
#include <string>

template<std::size_t N, std::size_t M, std::size_t P>
int mult(int A[N][M], int B[M][P])
static_assert(N > 1, "N must be greater than 1");
static_assert(M > 1, "M must be greater than 1");
static_assert(P > 1, "P must be greater than 1");

int C[N][P];

for (int n = 0; n < N; n++)
for (int p = 0; p < P; p++)
int num = 0;
for (int m = 0; m < M; m++)
num += A[n][m] * B[m][p];

C[n][p] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
int A[4][3]
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12
;

int B[3][2]
1, 2,
3, 4,
5, 6
;

mult<4, 3, 2>(A, B);
return 0;



The demo program outputs the $N times P$ ($4 times 2$) matrix product:



22 28
49 64
76 100
103 136





share|improve this answer























  • Thanks. But currently, in CppDroid, none of your code succeed in compilation..
    – Arief
    Feb 5 at 17:48










  • @Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
    – Null
    Feb 5 at 17:55














up vote
3
down vote



accepted










Avoid using namespace std



This can cause name collisions because it adds every name in the std namespace to the global namespace. For a small program like this one it's unlikely that you'll run into any problems (then again, maybe not) but it's best to get into the habit of using the std:: prefix on names in the std namespace.



Alternatively, you can introduce using declarations like using std::cout; to add specific names to the global namespace.



Avoid std::endl in favor of n



std::endl flushes the stream, which can cause a loss in performance.



Declare variables in the most local scope possible



You declare num at the beginning of mult() but you don't actually use it (and initialize it to 0) until you're inside the j loop. It's better to simply declare and initialize it in the same place and in the place where you start to use it.



I would also rename it to be more descriptive (e.g. sum or dot_product).



Avoid hard-coded numbers



Your code works with $4times 4$ matrices but you've got 4 hard-coded all over the place. You say




This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.




But there are a lot of instances where 4 needs to be replaced. At the very minimum you should define 4 as a constant and use that constant in the code:



const std::size_t N = 4; // or constexpr instead of const if your compiler supports it

int mult(int A[N][N], int B[N][N])
int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;



Now I just need to change the definition of N once to use a number other than 4.



Use static_assert to enforce the condition that $N > 1$



If your compiler supports static_assert you can ensure that $N > 1$ at compile time and cause a compilation failure with a simple message to explain the problem.



Function template



The multiplication algorithm is basically the same for any $N > 1$, so this function is a good candidate for a function template based on the dimension $N$. For example, you have A with N = 4, but in the same program you could have a matrix (2D array) D with N = 3 and the same code is used to multiply with both matrices. Here's a demo using a function template:



#include <iostream>
#include <string>

template<std::size_t N>
int mult(int A[N][N], int B[N][N])
static_assert(N > 1, "N must be greater than 1");

int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
const std::size_t N = 4;
int A[N][N];
int ind = 0;
std::cout << "Default Matrix A: n n";

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
A[i][j] = ind; ind++;
std::cout << A[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of A^2: n n";
mult<N>(A, A);

const std::size_t N2 = 3;
int D[N2][N2];
ind = 0;
std::cout << "nDefault Matrix D: n n";

for (int i = 0; i < N2; i++)
for (int j = 0; j < N2; j++)
D[i][j] = ind; ind++;
std::cout << D[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of D^2: n n";
mult<N2>(D, D);
return 0;



Consider a Matrix class instead of 2D arrays



Mathematical libraries implement matrices as a class. Internally, the Matrix class may use 2D arrays to store the data, but client code shouldn't depend on how that data is stored. A Matrix class can hide the implementation details from client code.



Extend to non-square matrices



In general, an $N times M$ matrix $A$ can be multiplied with a matrix $B$ if $B$ is $M times P$ ($A$ has $M$ columns and $B$ has $M$ rows, but otherwise the two matrices can have different dimensions). With a function template you can easily extend the multiplication function to support non-square matrices. Simply add the necessary template arguments and tweak the algorithm to use dimensions other than N. Here's a demo:



#include <iostream>
#include <string>

template<std::size_t N, std::size_t M, std::size_t P>
int mult(int A[N][M], int B[M][P])
static_assert(N > 1, "N must be greater than 1");
static_assert(M > 1, "M must be greater than 1");
static_assert(P > 1, "P must be greater than 1");

int C[N][P];

for (int n = 0; n < N; n++)
for (int p = 0; p < P; p++)
int num = 0;
for (int m = 0; m < M; m++)
num += A[n][m] * B[m][p];

C[n][p] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
int A[4][3]
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12
;

int B[3][2]
1, 2,
3, 4,
5, 6
;

mult<4, 3, 2>(A, B);
return 0;



The demo program outputs the $N times P$ ($4 times 2$) matrix product:



22 28
49 64
76 100
103 136





share|improve this answer























  • Thanks. But currently, in CppDroid, none of your code succeed in compilation..
    – Arief
    Feb 5 at 17:48










  • @Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
    – Null
    Feb 5 at 17:55












up vote
3
down vote



accepted







up vote
3
down vote



accepted






Avoid using namespace std



This can cause name collisions because it adds every name in the std namespace to the global namespace. For a small program like this one it's unlikely that you'll run into any problems (then again, maybe not) but it's best to get into the habit of using the std:: prefix on names in the std namespace.



Alternatively, you can introduce using declarations like using std::cout; to add specific names to the global namespace.



Avoid std::endl in favor of n



std::endl flushes the stream, which can cause a loss in performance.



Declare variables in the most local scope possible



You declare num at the beginning of mult() but you don't actually use it (and initialize it to 0) until you're inside the j loop. It's better to simply declare and initialize it in the same place and in the place where you start to use it.



I would also rename it to be more descriptive (e.g. sum or dot_product).



Avoid hard-coded numbers



Your code works with $4times 4$ matrices but you've got 4 hard-coded all over the place. You say




This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.




But there are a lot of instances where 4 needs to be replaced. At the very minimum you should define 4 as a constant and use that constant in the code:



const std::size_t N = 4; // or constexpr instead of const if your compiler supports it

int mult(int A[N][N], int B[N][N])
int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;



Now I just need to change the definition of N once to use a number other than 4.



Use static_assert to enforce the condition that $N > 1$



If your compiler supports static_assert you can ensure that $N > 1$ at compile time and cause a compilation failure with a simple message to explain the problem.



Function template



The multiplication algorithm is basically the same for any $N > 1$, so this function is a good candidate for a function template based on the dimension $N$. For example, you have A with N = 4, but in the same program you could have a matrix (2D array) D with N = 3 and the same code is used to multiply with both matrices. Here's a demo using a function template:



#include <iostream>
#include <string>

template<std::size_t N>
int mult(int A[N][N], int B[N][N])
static_assert(N > 1, "N must be greater than 1");

int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
const std::size_t N = 4;
int A[N][N];
int ind = 0;
std::cout << "Default Matrix A: n n";

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
A[i][j] = ind; ind++;
std::cout << A[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of A^2: n n";
mult<N>(A, A);

const std::size_t N2 = 3;
int D[N2][N2];
ind = 0;
std::cout << "nDefault Matrix D: n n";

for (int i = 0; i < N2; i++)
for (int j = 0; j < N2; j++)
D[i][j] = ind; ind++;
std::cout << D[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of D^2: n n";
mult<N2>(D, D);
return 0;



Consider a Matrix class instead of 2D arrays



Mathematical libraries implement matrices as a class. Internally, the Matrix class may use 2D arrays to store the data, but client code shouldn't depend on how that data is stored. A Matrix class can hide the implementation details from client code.



Extend to non-square matrices



In general, an $N times M$ matrix $A$ can be multiplied with a matrix $B$ if $B$ is $M times P$ ($A$ has $M$ columns and $B$ has $M$ rows, but otherwise the two matrices can have different dimensions). With a function template you can easily extend the multiplication function to support non-square matrices. Simply add the necessary template arguments and tweak the algorithm to use dimensions other than N. Here's a demo:



#include <iostream>
#include <string>

template<std::size_t N, std::size_t M, std::size_t P>
int mult(int A[N][M], int B[M][P])
static_assert(N > 1, "N must be greater than 1");
static_assert(M > 1, "M must be greater than 1");
static_assert(P > 1, "P must be greater than 1");

int C[N][P];

for (int n = 0; n < N; n++)
for (int p = 0; p < P; p++)
int num = 0;
for (int m = 0; m < M; m++)
num += A[n][m] * B[m][p];

C[n][p] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
int A[4][3]
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12
;

int B[3][2]
1, 2,
3, 4,
5, 6
;

mult<4, 3, 2>(A, B);
return 0;



The demo program outputs the $N times P$ ($4 times 2$) matrix product:



22 28
49 64
76 100
103 136





share|improve this answer















Avoid using namespace std



This can cause name collisions because it adds every name in the std namespace to the global namespace. For a small program like this one it's unlikely that you'll run into any problems (then again, maybe not) but it's best to get into the habit of using the std:: prefix on names in the std namespace.



Alternatively, you can introduce using declarations like using std::cout; to add specific names to the global namespace.



Avoid std::endl in favor of n



std::endl flushes the stream, which can cause a loss in performance.



Declare variables in the most local scope possible



You declare num at the beginning of mult() but you don't actually use it (and initialize it to 0) until you're inside the j loop. It's better to simply declare and initialize it in the same place and in the place where you start to use it.



I would also rename it to be more descriptive (e.g. sum or dot_product).



Avoid hard-coded numbers



Your code works with $4times 4$ matrices but you've got 4 hard-coded all over the place. You say




This can easily be generalized for any nxn matrix by replacing 4 with any positive number greater than 1.




But there are a lot of instances where 4 needs to be replaced. At the very minimum you should define 4 as a constant and use that constant in the code:



const std::size_t N = 4; // or constexpr instead of const if your compiler supports it

int mult(int A[N][N], int B[N][N])
int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;



Now I just need to change the definition of N once to use a number other than 4.



Use static_assert to enforce the condition that $N > 1$



If your compiler supports static_assert you can ensure that $N > 1$ at compile time and cause a compilation failure with a simple message to explain the problem.



Function template



The multiplication algorithm is basically the same for any $N > 1$, so this function is a good candidate for a function template based on the dimension $N$. For example, you have A with N = 4, but in the same program you could have a matrix (2D array) D with N = 3 and the same code is used to multiply with both matrices. Here's a demo using a function template:



#include <iostream>
#include <string>

template<std::size_t N>
int mult(int A[N][N], int B[N][N])
static_assert(N > 1, "N must be greater than 1");

int C[N][N];

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
int num = 0;
for (int k = 0; k < N; k++)
num += A[i][k] * B[k][j];

C[i][j] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
const std::size_t N = 4;
int A[N][N];
int ind = 0;
std::cout << "Default Matrix A: n n";

for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
A[i][j] = ind; ind++;
std::cout << A[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of A^2: n n";
mult<N>(A, A);

const std::size_t N2 = 3;
int D[N2][N2];
ind = 0;
std::cout << "nDefault Matrix D: n n";

for (int i = 0; i < N2; i++)
for (int j = 0; j < N2; j++)
D[i][j] = ind; ind++;
std::cout << D[i][j] << " ";

std::cout << std::endl;

std::cout << "nMultiplication of D^2: n n";
mult<N2>(D, D);
return 0;



Consider a Matrix class instead of 2D arrays



Mathematical libraries implement matrices as a class. Internally, the Matrix class may use 2D arrays to store the data, but client code shouldn't depend on how that data is stored. A Matrix class can hide the implementation details from client code.



Extend to non-square matrices



In general, an $N times M$ matrix $A$ can be multiplied with a matrix $B$ if $B$ is $M times P$ ($A$ has $M$ columns and $B$ has $M$ rows, but otherwise the two matrices can have different dimensions). With a function template you can easily extend the multiplication function to support non-square matrices. Simply add the necessary template arguments and tweak the algorithm to use dimensions other than N. Here's a demo:



#include <iostream>
#include <string>

template<std::size_t N, std::size_t M, std::size_t P>
int mult(int A[N][M], int B[M][P])
static_assert(N > 1, "N must be greater than 1");
static_assert(M > 1, "M must be greater than 1");
static_assert(P > 1, "P must be greater than 1");

int C[N][P];

for (int n = 0; n < N; n++)
for (int p = 0; p < P; p++)
int num = 0;
for (int m = 0; m < M; m++)
num += A[n][m] * B[m][p];

C[n][p] = num;
std::cout << num << " ";

std::cout << std::endl;


return 0;


int main()
int A[4][3]
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12
;

int B[3][2]
1, 2,
3, 4,
5, 6
;

mult<4, 3, 2>(A, B);
return 0;



The demo program outputs the $N times P$ ($4 times 2$) matrix product:



22 28
49 64
76 100
103 136






share|improve this answer















share|improve this answer



share|improve this answer








edited Feb 5 at 17:16


























answered Feb 5 at 17:04









Null

8572920




8572920











  • Thanks. But currently, in CppDroid, none of your code succeed in compilation..
    – Arief
    Feb 5 at 17:48










  • @Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
    – Null
    Feb 5 at 17:55
















  • Thanks. But currently, in CppDroid, none of your code succeed in compilation..
    – Arief
    Feb 5 at 17:48










  • @Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
    – Null
    Feb 5 at 17:55















Thanks. But currently, in CppDroid, none of your code succeed in compilation..
– Arief
Feb 5 at 17:48




Thanks. But currently, in CppDroid, none of your code succeed in compilation..
– Arief
Feb 5 at 17:48












@Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
– Null
Feb 5 at 17:55




@Arief mult() should compile if you remove the static_assert lines. The rest is just demonstration.
– Null
Feb 5 at 17:55












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186770%2fgeneral-nxn-matrix-multiplication-also-can-be-non-square%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation