I'm having an issue with compling the code.
I keep getting these errors.
"C: 194 warning passing argument 3 of 'matrix_column_subtract' makes pointer from integer without a cast"
"C: 12 note: expected 'double**' but argument is type 'int'
"C: 194 error too few arguments to function 'matrix_column_subtract'
I think I know what is going on I'm calling matrix_column_multiply is a void and I need to be calling it a pointer pointer I think and I don't know how to chage that. If anyone has some idea on how I can get this to compile that would be highly appreciated!!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEBUG 0
#define MAX_ITER 10000
double *eigen (int n, double **A);
void qr_decomp (int n, double **A, double **Q, double **R);
void matrix_copy_column(double **msrc, int col1, double **mdst,int col2, int rows);
void matrix_column_subtract(double **m1, int c1, double **m2, int c2, int rows);
void matrix_column_multiply(double **m, int c, double k, int rows);
int main() {
int i, n = 126;
double *eig, **Am;
FILE *BinInp, *TxtOut;
/* Input Code: Reads bv, Am in binary form from CGrad.bin */
if ( (BinInp = fopen("CGrad.bin","r")) == NULL ) {
fprintf(stderr, "Cannot open matrix binary file INPUT... exiting\n");
exit(-1);
}
Am = (double**)malloc (n*sizeof(double*));
Am[0] = (double*)malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Am[i] = Am[0] + i*n;
}
for (i = 0; i < n; i++) {
if (i==0) { /* Read one extra line that is discarded (bv is still in bin file) */
if (!fread(Am[i], sizeof(double), n, BinInp)) {
fprintf(stderr, "Cannot read row Am[%03d] of matrix... exiting\n", i+1);
exit(1);
}
}
if (!fread(Am[i], sizeof(double), n, BinInp)) {
fprintf(stderr, "Cannot read row Am[%03d] of matrix... exiting\n", i+1);
exit(1);
}
}
if (fclose(BinInp) == EOF) {
fprintf(stderr, "Cannot close matrix binary file INPUT... exiting\n");
exit(-1);
}
/* COMPUTE EIGENVALUES HERE USING FUNCTIONS. RETURN EIGENVALUES (AS 1D VECTOR) TO eig. */
if (DEBUG) printf ("Calling eigen\n");
eig = eigen (n, Am);
/* Output Code: Writes eig in text form to Eigs.txt */
if ( (TxtOut = fopen("Eigs.txt", "w")) == NULL ) {
fprintf(stderr, "Cannot open matrix text file OUTPUT... exiting\n");
exit(-1);
}
for (i = 0; i < n; i++) {
fprintf (TxtOut, "%18.14e ", eig[i]);
}
if (fclose(TxtOut) == EOF) {
fprintf(stderr, "Cannot close matrix text file INPUT... exiting\n");
exit(-1);
}
return 0;
}
double* eigen (int n, double **Acur)
{
double err = 1, eps = 1e-2;
double ndenom, nnumer, temp;
double *eig, **Anex, **Qsub, **Rsub;
int i, j, k, iters = 1;
/* Malloc memory for the three matricies */
Anex = malloc (n*sizeof(double*));
Anex[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Anex[i] = Anex[0] + i*n;
}
Qsub = malloc (n*sizeof(double*));
Qsub[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Qsub[i] = Qsub[0] + i*n;
}
Rsub = malloc (n*sizeof(double*));
Rsub[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
Rsub[i] = Rsub[0] + i*n;
}
/* Malloc memory for the return eig vector */
eig = malloc (n*sizeof(double));
for (i = 0; i < n; i++) {
eig[i] = 0;
}
/* Enter main iteration loop for eigenvalues */
while (err > eps && iters < MAX_ITER) {
/* QR Decompose Acur then find next iterate value in Anex */
qr_decomp (n, Acur, Qsub, Rsub);
// FIND NEXT ITERATE VALUE, PUT IN Anex.
/* Determine relative error change, reset "old" iterate value. */
ndenom = 0;
nnumer = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
temp = Anex[i][j]-Acur[i][j];
ndenom += temp*temp;
nnumer += Anex[i][j]*Anex[i][j];
Acur[i][j] = Anex[i][j];
}
}
err = sqrt(ndenom)/sqrt(nnumer);
/* Increment the iteration count and report error */
if (iters % 25 == 0) {
printf ("Error at end of iteration %05d = %14.10f %%\n", iters, 100*err);
}
++iters;
}
printf ("Error at end of iteration %05d = %14.10f\nCONVERGED.\n", iters-1, err);
if (iters == MAX_ITER) {
printf ("WARNING: MAX_ITER iterations reached!...\n");
}
/* Copy diagonal entries of Acur into eig for return to main */
for (i=0; i<n; i++) {
eig[i] = Acur[i][i];
}
return eig;
}
void qr_decomp (int n, double **Adec, double **myQ, double **myR)
{
int i, j, k; /* Loop Variables: this is all you should need! */
double **T, **S;
double r;
T = malloc (n*sizeof(double*));
T[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
T[i] = T[0] + i*n;
}
S = malloc (n*sizeof(double*));
S[0] = malloc (n*n*sizeof(double));
for (i = 1; i < n; ++i) {
S[i] = S[0] + i*n;
}
/* Main loop for decomposition */
for (i=0; i<n; i++) {
/* Column i of Q is initially column i of A */
matrix_copy_column(Adec,i,myQ,i,n);
/* For j < i-1, Perform the dot product between the j row of Q and the
i row of A to determine the R(j,i) value, then insure the Q i column
is orthogonal to all other Q columns by subtracting existing Q columns
from it. */
for (j = 0; j < i; j++) {
//r[j,i] = Qj^T * Ui
matrix_copy_column(myQ,j,T,0,n);
matrix_copy_column(Adec,i,S,0,n);
for (k=0; k<n; k++) {
r += T[k][0] * S[k][0];
}
/* Determine the R diagonal as the magnitude of the Q column, then
normalize the Q column (make it a unit vector). */
//Qi = Ui
myR[j][i] = r;
// Something wrong here.
// There is one parameter missing, as matrix_column_subtract needs 5 parameters and
// only 4 are given.
// Also, matrix_column_multiply is defined as returning a void, whereas the 3rd parameter
// of matrix_column_subtract should be a double **
matrix_column_subtract(myQ,i,matrix_column_multiply(T,0,r,n),j);
}
}
}
/* Copies a matrix column from msrc at column col1 to mdst at column col2 */
void matrix_copy_column(double **msrc, int col1, double **mdst,int col2, int rows) {
int i = 0;
for (i=0; i<rows; i++) {
mdst[i][col2] = msrc[i][col1];
}
}
/* Subtracts m2's column c2 from m1's column c1 */
void matrix_column_subtract(double **m1, int c1, double **m2, int c2, int rows) {
int i = 0;
for (i=0; i<rows; i++) {
m1[i][c1] -= m2[i][c2];
}
/*return m1;*/
}
void matrix_column_multiply(double **m, int c, double k, int rows) {
int i = 0;
for (i=0; i<rows; i++) {
m[i][c] *= k;
}
/*return m;*/
}
A problem is here.
matrix_column_subtract(myQ,i,matrix_column_multiply(T,0,r,n),j);
The relevant function signatures are:
void matrix_column_subtract(double **m1, int c1, double **m2, int c2, int rows);
void matrix_column_multiply(double **m, int c, double k, int rows);
Note that matrix_column_multiply returns void, but you're passing it in as if it were double **. I'm guessing the compiler is desperately trying to make it work and returned some sort of garbage integer.
These functions return void because they do their work directly on the matrix in question. matrix_column_multiply alters m. matrix_column_subtract alters m1.
To make it work, call matrix_column_multiply on T then pass T (now modified by the multiplication) into matrix_column_subtract.
matrix_column_multiply(T, 0, r, n);
matrix_column_subtract(myQ, i, T, j, ...rows...);
You're still missing the fifth argument, rows. I'm going to guess that's n, same as has been used for the rows in every other matrix_column_blah call.
Related
When I read the second vector using vector_read() function or by intializing it to zero by usign vector_init_zero() I get segementation fault. I have searched it alot still not got the answer why it's happening. If I use only one pointer and don't initiallize it to 0 it works fine. Every other function works fine with single variable of structure pointer.
#include <stdio.h>
#include <stdlib.h>
typedef struct vector_s
{
int dim;
float *data_ptr;
} vector_type;
/* Allocate and initialize to 0 a vector with the given dimension */
void vector_init_zeros(vector_type *v_ptr, int dim)
{
v_ptr->dim = dim;
v_ptr->data_ptr = (float *)calloc(dim, sizeof(float));
#ifdef DEBUG
if (v_ptr->data_ptr == 0)
{
printf("vector_init_zeros error: calloc returned a null ptr\n");
exit(1);
}
#endif
}
/* Free up a vector that was allocated using vector_init_zeros */
void vector_deinit(vector_type *v_ptr)
{
v_ptr->dim = 0;
free(v_ptr->data_ptr);
v_ptr->data_ptr = 0;
}
/* Attempt to read a vector from stdin. */
/* Returns 1 if read successful and 0 otherwise */
int vector_read(vector_type *v_ptr)
{
int i;
float next;
for (i = 0; i < v_ptr->dim; i++)
{
if (scanf("%g\n", &next) != 1)
{
return 0;
}
v_ptr->data_ptr[i] = next;
}
return 1;
}
/* w = u + v */
void vector_add(vector_type *u_ptr, vector_type *v_ptr,
vector_type *w_ptr)
{
int i;
for (i = 0; i < v_ptr->dim; i++)
{
w_ptr->data_ptr[i] = u_ptr->data_ptr[i] + v_ptr->data_ptr[i];
}
}
/* v = cv */
void vector_scalar_mult(vector_type *v_ptr, float c)
{
int i;
for (i = 0; i < v_ptr->dim; i++)
{
v_ptr->data_ptr[i] = v_ptr->data_ptr[i] * c;
}
}
/* print the compondents of the given vector */
void vector_print(vector_type *v_ptr)
{
int i;
for (i = 0; i < v_ptr->dim; i++)
{
printf("%f ", v_ptr->data_ptr[i]);
}
printf("\n");
}
int main()
{
int dim;
int count = 0;
if (scanf("%d", &dim) != 1)
{
printf("Error reading the vector dimension from stdin\n");
exit(1);
}
vector_type *s,*t;
vector_init_zeros(s, dim);
vector_init_zeros(t, dim);
vector_read(s);
vector_read(t);
}
In main() where you declare s and t, you never initialize them. You can either declare them as structure variables and pass their addresses to the functions with the & 'address of' operator or allocate and deallocate them with malloc() and free() or equivalents.
int main(){
...
vector_type s, t;
...
vector_init_zeros(&s, dim);
vector_init_zeros(&t, dim);
vector_read(&s);
vector_read(&t);
}
or
int main(){
...
vector_type *s, *t;
s = (vector_type *) malloc(sizeof(vector_type));
t = (vector_type *) malloc(sizeof(vector_type));
...
free(s);
free(t);
}
I have been given a school assignment in C to create a program that multiplies matrices. I will list assignment constraints below so people don't respond with questions as to why I am doing things this way.
Constraints from instructor:
Cannot use square brackets anywhere in code (use pointer notation instead)
Matrices A, B, C must be single integer pointer variables (int *A, *B, *C)
Can only use main function and those specified by header
Must compile with "gcc -ansi -Wall -o p2 p2.c"
I have not implemented the matrix multiplication function yet, as the issues I am having relate to either file reading or memory allocation.
The specific problem I am having is when I allocate space to the pointer matrix with either malloc OR calloc (tried both), the program inserts 33 in some places in the output instead of 0. I've tried everything at this point and am convinced my knowledge of pointers is fundamentally flawed.
p2.h (given by instructor)
#include <stdio.h>
#include <stdlib.h>
/* This function reads m, n, and p from the datafile.
It then allocates the correct amount of memory required for matrices
A, B, and C.
Then matrices A and B are filled from the datafile.
The values for m, n, and p are passed by reference, and are
thus filled in by this function
PARAMETERS in order are:
int ** matrix A
int ** matrix B
int ** matrix C
int * m The number of rows in matrix A
int * n The number of columns in matrix A and
The number of rows in matrix B
int * p The number of columns in matrix B
char * The name of the datafile, from the command line
*/
void read_matrices(int **, int **, int **, int *, int *, int *, char *);
/* This function prints a matrix. Rows and columns should be preserved.
PARAMETERS in order are:
int * The matrix to print
int The number of rows in the matrix
int The number of columns in the matrix
*/
void print_matrix(int *, int, int);
/* The two matrices A and B are multiplied, and matrix C contains the
result.
PARAMETERS in order are:
int * Matrix A
int * Matrix B
int * Matrix C
int m
int n
int p
*/
void mult_matrices(int *, int *, int *, int, int, int);
p2.c (sorry for the mess a lot of debugging went on)
#include <stdio.h>
#include <stdlib.h>
#include "./p2.h"
/* constants for testing */
#define cM 3
#define cN 2
#define cP 5
int main(int argc, char **argv) {
if (argc < 2) {
printf("Must include an argument.\n");
exit(1);
}
char *path = *(argv + 1);
int *m = (int *) malloc(sizeof(int));
int *n = (int *) malloc(sizeof(int));
int *p = (int *) malloc(sizeof(int));
*m = cM; *n = cN; *p = cP;
int i,j; /* loop counters */
/* allocate space for 2d pointer arrays */
int **A = NULL;
A = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(A+i) = (int *) malloc(*n * sizeof(int));
}
int **B = NULL;
B = (int **) malloc(*n * sizeof(int *));
for (i = 0; i < *n; i++) {
*(B+i) = (int *) malloc(*p * sizeof(int));
}
int **C = NULL;
C = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(C+i) = (int *) malloc(*p * sizeof(int));
}
/* write data to A */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
*(*(A+i)+j) = 0;
}
}
/* testing a */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
if (*(*(A+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to B */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
*(*(B+i)+j) = 0;
}
}
/* testing b */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
if (*(*(B+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to C */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
*(*(C+i)+j) = 0;
}
}
/* testing c */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
if (*(*(C+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
printf("Matrix A: \n");
print_matrix(*A, *m, *n);
printf("Matrix B: \n");
print_matrix(*B, *n, *p);
printf("Matrix C: \n");
print_matrix(*C, *m, *p);
return 0;
}
void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *path) {
FILE *fptr;
fptr = fopen(path, "r");
if (fptr == NULL) {
printf("Cannot open file: ./p2 [filename].txt\n");
exit(1);
}
/* get first 3 numbers from file, set m,n,p */
*m = fgetc(fptr);
fgetc(fptr);
*n = fgetc(fptr);
fgetc(fptr);
*p = fgetc(fptr);
fgetc(fptr);
/* read first matrix */
/* 1) calculate matrix size m x n
* 2) loop through malloc'ed matrix
* 3) each loop, insert char in loc
* 4) if next char NOT 10/32, add nextchar*10 to value in loc
*/
char cur;
while ( (cur = fgetc(fptr)) != EOF ) {
if (cur == 10 || cur == 32) {
/* do nothing :) */
} else {
*m = cur;
*n = cur;
*p = cur;
break;
}
}
printf("m: %c\n", *m);
printf("n: %c\n", *n);
printf("p: %c\n", *p);
printf("next: %c\n", fgetc(fptr));
fclose(fptr);
}
void print_matrix(int *X, int rows, int cols) {
int r, c;
int k = 0;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("\t%d", *(X+k));
k++;
}
printf("\n");
}
}
void mult_matrices(int *A, int *B, int *C, int m, int n, int p) {
}
d2.txt (data file)
3
2
4
1 2
3 4
5 6
7 8 9 10
11 12 13 14
Output: ./p2 d2.txt
[0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
Matrix A:
0 0
0 0
0 0
Matrix B:
0 0 0 0 0
0 33 0 0 0
Matrix C:
0 0 0 0 0
0 33 0 0 0
0 0 0 0 33
If you notice, I have some debug code that checks whether or not the current item in the array is 0. It seems to indicate that they are all 0, making me think it is a printing problem, but I am even more lost on what would be causing that. The ascii code for 33 is an exclamation point, but I am not sure what relevance it has.
Based on the function signatures you're supposed to use, you need to implement your 2D arrays as 1D with the correct index math. This will result in all memory being laid out contiguously, which is not at all guaranteed with the way you're allocating memory now (two calls to malloc for each matrix). For example:
#include <stdio.h>
#include <stdlib.h>
void print_matrix(int* A, int rows, int cols)
{
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
// If you want to treat A as a 2D matrix, this is where we have to do a bit of
// fancy index math to give you what double bracket notation [][] does for you
// r * cols gives you the index of the right row
// + c give you the column offset in that row
// add that offset to A then dereference
printf("%d\t", *(A + (r * cols + c)));
}
printf("\n");
}
}
int main(void)
{
// matrix A is supposed to be m by n
int* A;
// read these from file, or where ever they're supposed to come from
int m = 2;
int n = 10;
// Allocate the memory in one chunk. This makes the memory all contiguous, just the
// same as if you had done A[m][n]. However, the double call malloc for each int**
// matrix probably will not give you contiguous memory for the entire matrix. Each
// call to malloc is independent.
A = malloc(m * n * sizeof(int)); // or sizeof(*A) would be even better
if (A == NULL)
{
// handle error
}
// We can initialize values for A at this point, still not needing to care about
// rows or columns
for (int i=0; i<m*n; i++)
{
*(A + i) = i; // using i for a better visual when we print
}
print_matrix(A, m, n);
free(A);
return 0;
}
Demo
You are ovecomplicating simple things. Use pointers to arrays and allocate 2D array.
Use the correct type of your size variables.
Try to avoid side effects. Use parameters and function return values.
//this function is for the test purposes only
int writefile(const char *fn)
{
FILE *fo = fopen(fn, "w");
fprintf(fo,
"3\n"
"2\n"
"4\n"
"1 2\n"
"3 4\n"
"5 6\n"
"7 8 9 10\n"
"11 12 13 14\n");
fclose(fo);
}
void *allocIntMatrix(size_t rows, size_t cols)
{
int (*m)[cols] = malloc(rows * sizeof(*m));
return m;
}
void printIntMatrix(size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
printf("[%5d] ", m[row][col]);
}
printf("\n");
}
}
int readData(FILE *fi, size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
fscanf(fi, "%d", &m[row][col]);
}
}
return 0;
}
int main(int argc, char **argv)
{
size_t n,m,p;
writefile("a.aaa");
FILE *fi = fopen("a.aaa", "r");
fscanf(fi, "%zu", &m);
fscanf(fi, "%zu", &n);
fscanf(fi, "%zu", &p);
printf("n = %zu, m = %zu, p = %zu\n", n, m, p);
int (*A)[n] = allocIntMatrix(m, n);
int (*B)[p] = allocIntMatrix(n, p);
readData(fi, m, n, A);
readData(fi, n, p, B);
fclose(fi);
printIntMatrix(m, n, A);
printf("\n");
printIntMatrix(n, p, B);
return 0;
}
https://godbolt.org/z/adoEx1r4f
You need to check for errors (file, memory etc). I skipped it for the sake of simplicity of the example.
I have tried to write in C two functions.
The first, a function that gets two matrices (and their size) and returns their multiple matrix.
The second, a function that gets a matrix and her size and prints it.
Both of the function doesn't change the input matrices, so I want to get them as a const in the functions (but at the main theme, not const matrices).
The output fine, but the compiler throw me warnings(as shown below), all those, when I delete the const declaration in the function, it doesn't throw me any warnings.
is someone know why it throws me those warnings? and how can I fix this? (should I need to fix it?)
thank you
#include <stdio.h>
#include <stdlib.h>
int** multiple_matrix(int row1, int column1, int row2, int column2 ,const int mat1[][column1], const int mat2[][column2])
{
if((mat1 == NULL) || (mat2 == NULL))
{
printf("matrix equal to NULL, can't multiple!!!\n");
return NULL;
}
if (row2 != column1)
{
printf("number of columns in the first matrix is not equal to number of rows in second matrix, can't multiple!!! \n");
return NULL;
}
int i,k,j,sum;
int** res_mat = malloc (sizeof(int*) * row1);
for (i = 0; i<row1; ++i)
{
res_mat[i] = malloc (sizeof(int) * column2);
for (j = 0; j < column2; ++j)
{
sum = 0;
for (k = 0; k < column1; ++k)
{
sum += mat1[i][k] * mat2[k][j];
}
res_mat[i][j] = sum;
}
}
return res_mat;
}
void print_matrix( int** mat,size_t row, size_t column)
{
if(mat != NULL)
{
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
printf("%d ",mat[i][j]);
}
printf("\n");
}
}
else
{
printf("matrix is Null\n");
}
}
int main()
{
int matrix1[][3] ={{1,2,9},{3,4,9},{5,6,9}};
int matrix2[][3] = {{7,8,9},{10,11,12},{1,1,1}};
int matrix3[][1] ={{20},{30}};
int ** matrix4 =NULL;
size_t row1 = sizeof(matrix1)/sizeof(matrix1[0]);
size_t column1 = sizeof(matrix1[0])/sizeof(matrix1[0][0]);
size_t row2 = sizeof(matrix2)/sizeof(matrix2[0]);
size_t column2 = sizeof(matrix2[0])/sizeof(matrix2[0][0]);
size_t row3 = sizeof(matrix3)/sizeof(matrix3[0]);
size_t column3 = sizeof(matrix3[0])/sizeof(matrix3[0][0]);
printf("matrix1 is: %zu X %zu\n" ,row1,column1);
printf("matrix2 is: %zu X %zu\n" ,row2,column2);
printf("matrix3 is: %zu X %zu \n\n" ,row3,column3);
int** res1_matrix = multiple_matrix(row1,column1,row2,column2, matrix1, matrix2);
printf("Matrix1 X Matrix2:\n");
print_matrix(res1_matrix, row1, column2);
printf("\n\n");
int** res2_matrix = multiple_matrix(row1,column1,row3,column3, matrix1, matrix3);
printf("Matrix1 X Matrix3:\n");
print_matrix(res2_matrix, row1, column3);
printf("\n\n");
return 0;
}
the warnings that I get when I use the const in the functions
Im currently trying to finish an assignment in which you use pthreads to speed up the matrix multiplication. The idea is to have the pthreads each work on there chunk of rows
For example: 1000 rows and 4 threads would be thread 0 : rows 0-249, thread 1: 250-499, thread 2: 500-749 and thread 3: 750-999
blocksOfWork = (BLOCK *) malloc(numberOfThreads*sizeof(BLOCK));
for(i=0; i < numberOfThreads; i++){
blocksOfWork[i].threadId = i;
blocksOfWork[i].start_row = i * rows/numberOfThreads;
if (i == numberOfThreads -1){
blocksOfWork[i].end_row = rows - 1;
}
else{
blocksOfWork[i].end_row = (i+1)*rows/numberOfThreads -1;
}
blocksOfWork[i].start_col = 0;
blocksOfWork[i].end_col = columns -1;
}
I'm just having a hard time understanding on how to perform the matrix multiplication iteration, I've put a print statement for debugging purpose but I still can't figure it out, ThreadMMulti Function. Any helpful tips in the right direction would be appreciated. Here is the full code
/*Program to generate two square 2D arrays of random doubles and
time their multiplication.
Program utlizies pthreads to efficiently perform matrix Multiplication
Compile by: gcc -o mmult -O3 mmultHW6.c -lpthread
Run by: ./mmult 1000 1000 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>
#define TRUE 1
#define FALSE 0
#define BOOL int
typedef struct {
int threadId;
int start_row;
int end_row;
int start_col;
int end_col;
} BLOCK;
// function prototypes
double ** allocate2DArray(int rows, int columns);
void print2DArray(int rows, int columns, double ** array2D);
void generateRandom2DArray(int rows, int columns,
double min, double max, double ** random2DArray);
BOOL equal2DArrays(int rows, int columns, double ** array1, double ** array2,
double tolerance);
void matrixMultiplication(int rows1, int columns1, double ** array1,
int rows2, int columns2, double ** array2,
double ** product);
void matrixMultiplicationAlt(int rows1, int columns1, double ** array1,
int rows2, int columns2, double ** array2,
double ** product);
void * threadMMult(void * rank);
int numberOfThreads;
double ** A;
double ** B;
double ** C;
double ** C_alt;
int rows, columns;
int main(int argc, char ** argv) {
long i, startTime, endTime,seqTime, paralellTime;
BLOCK * blocksOfWork;
int errorCode;
double tolerence;
pthread_t * threadHandles;
if (argc !=3) {
printf("Usage: %s <# of rows><# of columns><# of Threads>\n", argv[0]);
exit(-1);
} // end if
sscanf(argv[1], "%d", &rows);
sscanf(argv[1], "%d", &numberOfThreads);
columns = rows;
// seed the random number generator
srand( time(NULL) );
A = allocate2DArray(rows, columns);
B = allocate2DArray(rows, columns);
C = allocate2DArray(rows, columns);
C_alt = allocate2DArray(rows, columns);
generateRandom2DArray(rows, columns, -1.0, +1.0, A);
generateRandom2DArray(rows, columns, -1.0, +1.0, B);
printf("after initializing matrices\n");
time(&startTime);
matrixMultiplicationAlt(rows, columns, A, rows, columns, B, C_alt);
time(&endTime);
seqTime = endTime-startTime;
printf("Matrix Multiplication Alt. time = %ld\n",seqTime);
time(&startTime);
threadHandles = (pthread_t *)
malloc(numberOfThreads*sizeof(pthread_t));
blocksOfWork = (BLOCK *) malloc(numberOfThreads*sizeof(BLOCK));
for(i=0; i < numberOfThreads; i++){
blocksOfWork[i].threadId = i;
blocksOfWork[i].start_row = i * rows/numberOfThreads;
if (i == numberOfThreads -1){
blocksOfWork[i].end_row = rows - 1;
}
else{
blocksOfWork[i].end_row = (i+1)*rows/numberOfThreads -1;
}
blocksOfWork[i].start_col = 0;
blocksOfWork[i].end_col = columns -1;
}
for (i=0; i < numberOfThreads; i++) {
if (errorCode = pthread_create(&threadHandles[i], NULL, threadMMult,
&blocksOfWork[i]) != 0) {
printf("pthread %d failed to be created with error code %d\n", i, errorCode);
} // end if
} // end for
for (i=0; i < numberOfThreads; i++) {
if (errorCode = pthread_join(threadHandles[i], (void **) NULL) != 0) {
printf("pthread %d failed to be joined with error code %d\n", i, errorCode);
} // end if
} // end for
time(&endTime);
paralellTime = endTime-startTime;
printf("Parallel Matrix Multiplication time = %ld\n",paralellTime);
if (equal2DArrays(rows, columns, C, C_alt, 0.000001)) {
printf("Arrays match with tolerance of %.000001f\n", 0.000001);
} else {
printf("Arrays DON'T match with tolerance of %.000001f\n", 0.000001);
} // end if
return 0;
} // end main
void * threadMMult(void * arg){
BLOCK * block = (BLOCK *) arg;
int threadId = block->threadId;
int startRow = block->start_row;
int endRow = block->end_row;
int startCol = block->start_col;
int endCol = block->end_col;
int i, j, k, sum;
for (int i=startRow; i<=endRow;i++){
for (int j = startCol; j<=endCol; j++){
//C[i][j] = 0;
for(int k=0; k<= columns-1; k++){
//C[i][j] += A[i][k]*B[k][j];
printf("%lu - C[%d][%d] += A[%d][%d]*B[%d][%d]\n", pthread_self()
, i,j,i,k,k,j);
}
}
}
}
/*******************************************************************
* Function matrixMultiplicationAlt passed two matrices and returns
* their product.
********************************************************************/
void matrixMultiplicationAlt(int rows1, int columns1, double ** array1,
int rows2, int columns2, double ** array2,
double ** product) {
int i, j, k;
double ** array2_transpose;
if (columns1 != rows2) {
printf("Matrices cannot be multiplied -- incompatible dimensions!\n");
exit(-1);
} // end if
// Transposes array2
array2_transpose = allocate2DArray(columns2, rows2);
for (i=0; i < rows2; i++) {
for (j=0; j < columns2; j++) {
array2_transpose[j][i] = array2[i][j];
} /* end for (j */
} /* end for (i */
// Matrix Multiplication uses array1 and array2_transpose
for (i=0; i < rows1; i++) {
for (j=0; j < columns2; j++) {
product[i][j] = 0.0;
for (k=0; k < columns1; k++) {
product[i][j] += array1[i][k]*array2_transpose[j][k];
} /* end for (k */
} /* end for (j */
} /* end for (i */
} // end matrixMultiplicationAlt
/*******************************************************************
* Function allocate2DArray dynamically allocates a 2D array of
* size rows x columns, and returns it.
********************************************************************/
double ** allocate2DArray(int rows, int columns) {
double ** local2DArray;
int r;
local2DArray = (double **) malloc(sizeof(double *)*rows);
for (r=0; r < rows; r++) {
local2DArray[r] = (double *) malloc(sizeof(double)*columns);
} // end for
return local2DArray;
} // end allocate2DArray
/*******************************************************************
* Function generateRandom2DArray is passed the # rows, the # columns,
* min. value, max. value, and returns random2DArray containing
* randomly generated doubles.
********************************************************************/
void generateRandom2DArray(int rows, int columns,
double min, double max, double ** random2DArray) {
int r, c;
double range, div;
for (r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
range = max - min;
div = RAND_MAX / range;
random2DArray[r][c] = min + (rand() / div);
} // end for (c...
} // end for (r...
} // end generateRandom2DArray
/*******************************************************************
* Function print2DArray is passed the # rows, # columns, and the
* array2D. It prints the 2D array to the screen.
********************************************************************/
void print2DArray(int rows, int columns, double ** array2D) {
int r, c;
for(r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
printf("%10.5lf", array2D[r][c]);
} // end for (c...
printf("\n");
} // end for(r...
} // end print2DArray
/*******************************************************************
* Function equal2DArrays is passed the # rows, # columns, two
* array2Ds, and tolerance. It returns TRUE if corresponding array
* elements are equal within the specified tolerance; otherwise it
* returns FALSE.
********************************************************************/
BOOL equal2DArrays(int rows, int columns, double ** array1, double ** array2,
double tolerance) {
int r, c;
for(r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
if (fabs(array1[r][c] - array2[r][c]) > tolerance) {
return FALSE;
} // end if
} // end for (c...
} // end for(r...
return TRUE;
} // end equal2DArray
So I created a program that calculates matrix multiplication sequentially then records the time, then calculates matrix multiplication using any number of pthreads entered in the command line numberOfThreads. But regardless of how many threads I enter it still giving me the same time each time. I'm currently on i7 Macbook so I'm not sure if thats why adding more threads doesn't optimize the calculations or If I just don't have the correct program.
Heres the code:
/*Program to generate two square 2D arrays of random doubles and
time their multiplication.
Program utlizies pthreads to efficiently perform matrix Multiplication
Compile by: gcc -o mmult -O3 mmultHW6.c -lpthread
Run by: ./mmult 1000 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>
#define TRUE 1
#define FALSE 0
#define BOOL int
typedef struct {
int threadId;
int start_row;
int end_row;
int start_col;
int end_col;
} BLOCK;
// function prototypes
double ** allocate2DArray(int rows, int columns);
void print2DArray(int rows, int columns, double ** array2D);
void generateRandom2DArray(int rows, int columns,
double min, double max, double ** random2DArray);
BOOL equal2DArrays(int rows, int columns, double ** array1, double ** array2,
double tolerance);
void matrixMultiplication(int rows1, int columns1, double ** array1,
int rows2, int columns2, double ** array2,
double ** product);
void matrixMultiplicationAlt(int rows1, int columns1, double ** array1,
int rows2, int columns2, double ** array2,
double ** product);
void * threadMMult(void * rank);
int numberOfThreads;
double ** A;
double ** B;
double ** C;
double ** C_alt;
int rows, columns;
int main(int argc, char ** argv) {
long i, startTime, endTime,seqTime, paralellTime;
BLOCK * blocksOfWork;
int errorCode;
double tolerence;
pthread_t * threadHandles;
if (argc !=3) {
printf("Usage: %s <# of rows><# of Threads>\n", argv[0]);
exit(-1);
} // end if
sscanf(argv[1], "%d", &rows);
sscanf(argv[1], "%d", &numberOfThreads);
columns = rows;
// seed the random number generator
srand( time(NULL) );
A = allocate2DArray(rows, columns);
B = allocate2DArray(rows, columns);
C = allocate2DArray(rows, columns);
C_alt = allocate2DArray(rows, columns);
generateRandom2DArray(rows, columns, -1.0, +1.0, A);
generateRandom2DArray(rows, columns, -1.0, +1.0, B);
printf("after initializing matrices\n");
time(&startTime);
matrixMultiplicationAlt(rows, columns, A, rows, columns, B, C_alt);
time(&endTime);
seqTime = endTime-startTime;
printf("Matrix Multiplication Alt. time = %ld\n",seqTime);
time(&startTime);
threadHandles = (pthread_t *) malloc(numberOfThreads*sizeof(pthread_t));
blocksOfWork = (BLOCK *) malloc(numberOfThreads*sizeof(BLOCK));
for(i=0; i < numberOfThreads; i++){
blocksOfWork[i].threadId = i;
blocksOfWork[i].start_row = i * rows/numberOfThreads;
if (i == numberOfThreads -1){
blocksOfWork[i].end_row = rows - 1;
}
else{
blocksOfWork[i].end_row = (i+1)*rows/numberOfThreads -1;
}
}
for (i=0; i < numberOfThreads; i++) {
if (errorCode = pthread_create(&threadHandles[i], NULL, threadMMult,
&blocksOfWork[i]) != 0) {
printf("pthread %d failed to be created with error code %d\n", i, errorCode);
} // end if
} // end for
for (i=0; i < numberOfThreads; i++) {
if (errorCode = pthread_join(threadHandles[i], (void **) NULL) != 0) {
printf("pthread %d failed to be joined with error code %d\n", i, errorCode);
} // end if
} // end for
time(&endTime);
paralellTime = endTime-startTime;
printf("Parallel Matrix Multiplication time = %ld\n",paralellTime);
if (equal2DArrays(rows, columns, C, C_alt, 0.000001)) {
printf("Arrays match with tolerance of %.000001f\n", 0.000001);
} else {
printf("Arrays DON'T match with tolerance of %.000001f\n", 0.000001);
} // end if
return 0;
} // end main
void * threadMMult(void * arg){
BLOCK * block = (BLOCK *) arg;
int threadId = block->threadId;
int startRow = block->start_row;
int endRow = block->end_row;
int i, j, k, sum;
for(i=startRow; i<=endRow;i++){
for(j = 0; j<rows;j++){
C[i][j] = 0;
for(k=0; k<rows ; k++){
C[i][j] += A[i][k]*B[k][j];
//printf("%lu - C[%d][%d] += A[%d][%d] * B[%d][%d]\n",
//pthread_self(), i,j,i,k,k,j);
}
}
return 0;
}
}
//C[i][j] += A[i][k] * B_transpose[j][k];
/*******************************************************************
* Function matrixMultiplicationAlt passed two matrices and returns
* their product.
********************************************************************/
void matrixMultiplicationAlt(int rows1, int columns1, double ** array1,
int rows2, int columns2, double ** array2,
double ** product) {
int i, j, k;
double ** array2_transpose;
if (columns1 != rows2) {
printf("Matrices cannot be multiplied -- incompatible dimensions!\n");
exit(-1);
} // end if
// Transposes array2
array2_transpose = allocate2DArray(columns2, rows2);
for (i=0; i < rows2; i++) {
for (j=0; j < columns2; j++) {
array2_transpose[j][i] = array2[i][j];
} /* end for (j */
} /* end for (i */
// Matrix Multiplication uses array1 and array2_transpose
for (i=0; i < rows1; i++) {
for (j=0; j < columns2; j++) {
C_alt[i][j] = 0.0;
for (k=0; k < columns1; k++) {
C_alt[i][j] += array1[i][k]*array2_transpose[j][k];
} /* end for (k */
} /* end for (j */
} /* end for (i */
} // end matrixMultiplicationAlt
/*******************************************************************
* Function allocate2DArray dynamically allocates a 2D array of
* size rows x columns, and returns it.
********************************************************************/
double ** allocate2DArray(int rows, int columns) {
double ** local2DArray;
int r;
local2DArray = (double **) malloc(sizeof(double *)*rows);
for (r=0; r < rows; r++) {
local2DArray[r] = (double *) malloc(sizeof(double)*columns);
} // end for
return local2DArray;
} // end allocate2DArray
/*******************************************************************
* Function generateRandom2DArray is passed the # rows, the # columns,
* min. value, max. value, and returns random2DArray containing
* randomly generated doubles.
********************************************************************/
void generateRandom2DArray(int rows, int columns,
double min, double max, double ** random2DArray) {
int r, c;
double range, div;
for (r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
range = max - min;
div = RAND_MAX / range;
random2DArray[r][c] = min + (rand() / div);
} // end for (c...
} // end for (r...
} // end generateRandom2DArray
/*******************************************************************
* Function print2DArray is passed the # rows, # columns, and the
* array2D. It prints the 2D array to the screen.
********************************************************************/
void print2DArray(int rows, int columns, double ** array2D) {
int r, c;
for(r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
printf("%10.5lf", array2D[r][c]);
} // end for (c...
printf("\n");
} // end for(r...
} // end print2DArray
/*******************************************************************
* Function equal2DArrays is passed the # rows, # columns, two
* array2Ds, and tolerance. It returns TRUE if corresponding array
* elements are equal within the specified tolerance; otherwise it
* returns FALSE.
********************************************************************/
BOOL equal2DArrays(int rows, int columns, double ** array1, double ** array2,
double tolerance) {
int r, c;
for(r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
if (fabs(array1[r][c] - array2[r][c]) > tolerance) {
return FALSE;
} // end if
} // end for (c...
} // end for(r...
return TRUE;
} // end equal2DArray
This is a bit suspicious:
sscanf(argv[1], "%d", &rows);
sscanf(argv[1], "%d", &numberOfThreads);
I am not sure where you are with the learning C thing, but “man 3 getopt” should show a much better way to pass runtime parameters into your program than accidentally re-using argv[1]....
The second problem that you have created is using two different mechanisms for performing matrix multiplication; one for the sequential version, and a separate one for the parallel one. Logically, you should be able to have one, fully parameterized function to perform the operation, then the fact that M parallel threads are invoking it with different data is transparent to the function itself. Since you didn’t, you left a question mark: is the lack of scale because one of your matrix multiply functions doesn’t work correctly?
Looking at your code, I have little faith that it does; you have utilized a barrage of mechanisms to implement this. The core is:
Mult(double *A, int Ar, int Ac, double *B, int Br, int Bc, double C, int Cr, int Cc) {
/ multiply C = A * B */
}
and whether it is N threads converging on a solution, or one thread trudging through the solution, they should be able to execute the same code.