Good day! First of all, sorry as this is a long (and maybe stupid) question from a new (and noob) programer.
I am trying to do a program that multiply 2 matrices, and I wanted to use functions to do it. So far so good, I have learned how to pass 2D arrays to function using pointer. However, when I try to multiply the value of the respective row with that of the column of the 2nd matrix, I keep getting the different result from what I have calculated by myself. Here's the function:
This one is to input value for matrices, please pay attention to the "cin" line.
void nhapMT (int *A, int m, int n) {
for (int i = 0; i < m; i ){
for (int j = 0; j < n; j ){
cout << "\nNhap phan tu dong " << 1 i << " cot " << 1 j << ": "; //Just inputing value of row i and column j for matrices
cin >> *(A i*n j);
}
}
}
And this one is to multiply the value of the respective row with that of the column the 2nd matrix
void MP (int *A, int *B, int *Tich, int Phu[], int m, int n, int p, int q) { //m and n is the size of row and column of matrix A; n and p is that of B and Tich is the product matrix of them
int a, b, c, d; //I use a, b, c as the counter to m, n and p; d is the counter to q
a = b = c = 0;
q = m*n*p;
Phu[q]; //q = the number of element of the resulting matrix, this array is for me to check if the result of multiplying 1 by 1 was correct before adding them to use for the result matrix
for (d = 0; d < q; d ) {
Phu[d] = *(A a*n b) * *(B b*p c);
b ;
if (b == n - 1) {
c ;
}if (b == n - 1 && c == p - 1) {
a ;
}if (b == n - 1 && a == m - 1 && c == p - 1){
break;
}
}
for (int i = 0; i < q; i ) {
cout << Phu[i] << endl; // just checking the result
}
}
ummmm.... apparently I wrote the multiply function last night and delete it for the new code today so umm.... I forgot how I wrote it. This one is just the replica (the result of this version is just pure wrong), but I swear it was kinda like that. Anyhoo, the point here is: when I cout the "Phu" array last night, the result was decent and "looks legit" number. It just wasn't the correct answer. For example, the answer was: {2, 2, 3, 4, 6, 1, 9, 2}. But the cout-ed version of it was like {2, 2, 6, 9, 2, 3, 4, 1} (kinda, sry I'm stupid). I noticed they were the elements of the correct result, they were just in wrong order. I tried changing it from *(A a*n b)
to *((A a) b)
but the result is still the same.
Fast forward to today, I tried to find the root of the problem, by not cout-ing the result, but the operand *((A a) b)
(by incrementing a and b), and would you look at that! The result was NOT in order! Okay, I have already known a bit about the concept of "multidimensional array actually is multiplie 1D arrays". I'm using two (2x2) matrices to test out this, so A = {(1,2),(3,1)} and B = {(2,3),(1,2)}. In my assumption, *((A 0) 0)
is 1 (which is correct) and *((A 1) 0)
should be 3. (which is not, in fact, it's "2" a.k.a *((A 0) 1)
). That made me check the rest to see if it was the same as the 3rd element (or the first element of the second 1D array). I found out that *((A 0) 2)
is just the same as *((A 2) 0)
Instead of this. (I mean, *((A 2) 0)
should have printed some gibberish or printed nothing, right?), it's like two 1D arrays is merged into one like this (and I think it's the case here).
Enough with the context, I'm sure at this point 99% people have left, if you're still reading, thank you. Now the question:
In the "NhapMT" function, if I change
*(A i*n j);
to*((A i) j);
the value of the elements inside the matrix came out different from what I have input, what's the reason between that and can someone explain the multiplying with "n" part in*(A i*n j);
to me as I still don't get it.What's the reason behind two 1D arrays being merged into one big 1D array in the "MP" function? Is it because I'm using the pointer directly instead of giving the pointer a name?
Again, thank you for reading that mess of the code and even if you're not going to answer this, I hope you have a nice day.
CodePudding user response:
For the first question i can say (A in j) will reach A[i*n][j] and *((A i) j) will reach A[i][j], why didn't you use **A? It doesn't make sense to reach a 2D function by this way actually. You shouldn't even care about this and guess memory alignments, this usage requires you to also know that and you can never know.
All you need to do will be A[i][j], remember that using [] is legal for *A. C/C allows this notation as well. First take a look at the following question, it'll make things so much easier.
passing 2d array using pointers
Come to 2nd question, it is just matrix multiplication rule. Multiplicand's row and multiplier's column is multiplied and sum of the products is written as the product's element respectively.
Here's a sample I wrote to help you, hope it does.
int multiply(int *row, int *column, int m, int n)
{
int element = 0;
//Just multiplies row and returns element for product
for(int i = 0; i < m; i )
{
for(int j = 0; j < n; j )
{
element = row[i]*column[j];
}
}
return element;
}
For getting the column you can transpose the multiplier matrix and reach it's column like this.
int transpose[m][n];
for (int i = 0; i < m; i )
{
for (int j = 0; j < n; j ) {
transpose[j][i] = array[i][j];
}
}
int *pointer_for_first_column = transpose[0];
int *pointer_for_first_row = array[0];
Then just call the function and check the result, have a nice day.
cout << multiply(pointer_for_first_row, pointer_for_first_column, m, n);
CodePudding user response:
First of all, please, stop using pointer arithmetic unless you have a reason to. *(A a*b b)
is just A[a*n b]
and in other places too, so please do that. This will make your code a lot more readable.
Second, I don't see how your function was supposed to work correctly in the first place. As I understand it, you put your result in Phu
, but I don't see any addition to Phu
elements in your code only assignment.
I also don't see why did you use so many counters, and why do you have two product arguments in your function prototype but only use one.
Assuming you got all of the indices right in your code, you might want to try and change
Phu[d] = *(A a*n b) * *(B b*p c);
to
Phu[d] = *(A a*n b) * *(B b*p c);
but even if this works you'd probably want to re-write your function because it's really not how you're supposed to write even a simple matrix multiplication.
How you probably should do it
A classic algorithm for matrix multiplication is:
for (i = 0; i < N; i)
for (j = 0; j < M; j)
for (k = 0; k < K; k)
result[i][j] = A[i][k] * B[k][j];
Notice that the amount of columns of A must be equal to the amount of rows of B (that's how matrix multiplication is defined in mathematics), so instead of 4 size arguments you only need to pass 3: N
for rows of A
, K
for columns of A
and rows of B
, and M
for columns of B
. Your resulting matrix will have the size NxM.
If you're actually using C-style 2D arrays to store rows of matrices, then for 2D array indices A[i][j]
you will have A[i * K j]
and for B[i][j]
- B[i * M j]
(each row has a number of integers equal to the number of columns in a matrix, so i
rows should offset your pointer by i * COLUMNS
integers, and then you add j
to go to the needed column).
Your function therefore should look something like this:
void matmul(int* A, int* B, int* result, int N, int K, int M) {
for (int i = 0; i < N; i)
for (int j = 0; j < M; j)
for (int k = 0; k < K; k)
result[i][j] = A[i][k] * B[k][j];
}
Here, of course, you just trust that A
, B
and result
are pointers to an actually existing memory with actually corresponding size and since you're learning C a good task for later should be to write a class that takes care of all that.