Files
Toooba/Tests/isa/Cprograms/benchmark/matrixmul/matrixmul.c
2026-04-16 13:51:31 +01:00

205 lines
5.8 KiB
C

// Source: https://github.com/ivanbgd/Matrix-Multiplication-MatMul-C/blob/master/matmul_1d_seq.c
#define MATMUL_1D
#ifdef MATMUL_1D
/* Matrices are represented as 1-D arrays in memory.
* That means they are contiguous in memory.
* Minimum dimension is 1, not 0, and internal dimensions must match. */
#include <math.h>
// #include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void free(void *ptr);
void *malloc(size_t size);
/* Initializes vector or matrix, sequentially, with indices. */
void init_seq(double *a, const unsigned n_rows_a, const unsigned n_cols_a) {
for (size_t i = 0; i < n_rows_a; i++) {
for (size_t j = 0; j < n_cols_a; j++) {
a[i*n_cols_a + j] = i*n_cols_a + j;
}
}
}
// static unsigned int seed = 123456789; // must be initialized somehow
// unsigned int rand_test(void)
// {
// seed = (1103515245 * seed + 12345);
// return (seed >> 16) & 0x7FFF; // 15-bit result
// }
// /* Initializes vector or matrix, randomly. */
// void init_rand(double *a, const unsigned n_rows_a, const unsigned n_cols_a) {
// for (size_t i = 0; i < n_rows_a; i++) {
// for (size_t j = 0; j < n_cols_a; j++) {
// a[i*n_cols_a + j] = rand_test() / 32767.0;
// // rand_test() / (double)RAND_MAX;
// }
// }
// }
/* Takes and returns a new matrix, t, which is a transpose of the original one, m.
It's also flat in memory, i.e., 1-D, but it should be looked at as a transpose
of m, meaning, n_rows_t == n_cols_m, and n_cols_t == n_rows_m.
The original matrix m stays intact. */
double *transpose(const double *m, const unsigned n_rows_m, const unsigned n_cols_m, double *t) {
for (size_t i = 0; i < n_rows_m; i++) {
for (size_t j = 0; j < n_cols_m; j++) {
t[j*n_rows_m + i] = m[i*n_cols_m + j];
}
}
return t;
}
/* Dot product of two arrays, or matrix product
* Allocates and returns an array.
* This variant doesn't transpose matrix b, and it's a lot slower. */
double *dot_simple(const double *a, const unsigned n_rows_a, const unsigned n_cols_a,\
const double *b, const unsigned n_rows_b, const unsigned n_cols_b) {
if (n_cols_a != n_rows_b) {
// printf("#columns A must be equal to #rows B!\n");
// system("pause");
// exit(-2);
}
double *c = malloc(n_rows_a * n_cols_b * sizeof(*c));
if (c == NULL) {
// printf("Couldn't allocate memory!\n");
// system("pause");
// exit(-1);
}
for (size_t i = 0; i < n_rows_a; i++) {
for (size_t k = 0; k < n_cols_b; k++) {
double sum = 0.0;
for (size_t j = 0; j < n_cols_a; j++) {
sum += a[i*n_cols_a + j] * b[j*n_cols_b + k];
}
c[i*n_cols_b + k] = sum;
}
}
return c;
}
/* Dot product of two arrays, or matrix product
* Allocates and returns an array.
* This variant transposes matrix b, and it's a lot faster. */
double *dot(const double *a, const unsigned n_rows_a, const unsigned n_cols_a, \
const double *b, const unsigned n_rows_b, const unsigned n_cols_b) {
if (n_cols_a != n_rows_b) {
// printf("#columns A must be equal to #rows B!\n");
// system("pause");
// exit(-2);
}
double *bt = malloc(n_rows_b * n_cols_b * sizeof(*b));
double *c = malloc(n_rows_a * n_cols_b * sizeof(*c));
if ((c == NULL) || (bt == NULL)) {
// printf("Couldn't allocate memory!\n");
// system("pause");
// exit(-1);
}
bt = transpose(b, n_rows_b, n_cols_b, bt);
for (size_t i = 0; i < n_rows_a; i++) {
for (size_t k = 0; k < n_cols_b; k++) {
double sum = 0.0;
for (size_t j = 0; j < n_cols_a; j++) {
sum += a[i*n_cols_a + j] * bt[k*n_rows_b + j];
}
c[i*n_cols_b + k] = sum;
}
}
free(bt);
return c;
}
/* Prints vector, or matrix. */
// void print(const double *a, const unsigned n_rows_a, const unsigned n_cols_a) {
// for (size_t i = 0; i < n_rows_a; i++) {
// for (size_t j = 0; j < n_cols_a; j++) {
// printf("%8.3f ", a[i*n_cols_a + j]);
// }
// printf("\n");
// }
// printf("\n");
// }
int main(void) {
/* Intializes random number generator */
// time_t t;
// srand((unsigned)time(&t));
// srand(0);
/* For measuring time */
double t0, t1;
const unsigned scale = 1;
const unsigned n_rows_a = 4 * scale;
const unsigned n_cols_a = 3 * scale;
const unsigned n_rows_b = 3 * scale;
const unsigned n_cols_b = 2 * scale;
double *a = malloc(n_rows_a * n_cols_a * sizeof(*a));
double *b = malloc(n_rows_b * n_cols_b * sizeof(*b));
double *c = NULL;
double *d = NULL;
if (!a || !b) {
// printf("Couldn't allocate memory!\n");
// system("pause");
// exit(-1);
}
// init_rand(a, n_rows_a, n_cols_a);
// init_rand(b, n_rows_b, n_cols_b);
init_seq(a, n_rows_a, n_cols_a);
init_seq(b, n_rows_b, n_cols_b);
// t0 = omp_get_wtime();
c = dot_simple(a, n_rows_a, n_cols_a, b, n_rows_b, n_cols_b);
// t1 = omp_get_wtime();
// printf("Dot Simple: Elapsed time %.3f s\n", t1 - t0);
// t0 = omp_get_wtime();
d = dot(a, n_rows_a, n_cols_a, b, n_rows_b, n_cols_b);
// t1 = omp_get_wtime();
// printf("Dot: Elapsed time %.3f s\n", t1 - t0);
if (scale == 1) {
// printf("Matrix A:\n");
// print(a, n_rows_a, n_cols_a);
// // printf("Matrix B:\n");
// print(b, n_rows_b, n_cols_b);
// // printf("Matrix C:\n");
// print(c, n_rows_a, n_cols_b);
// // printf("Matrix D:\n");
// print(d, n_rows_a, n_cols_b);
}
free(a);
free(b);
free(c);
free(d);
// system("pause");
return(0);
}
#endif // MATMUL_1D