#include <stdio.h>
#include <stdlib.h>
#define LONG_LINE_SIZE 8000
#define SHORT_LINE_SIZE 80
typedef enum
{
ROW_ORDER = 0,
COL_ORDER
} MAT_ORDER_T;
typedef int ELEMENT_T;
#define ELEMENT_SCAN_STRING "%d"
#define ELEMENT_PRINT_STRING "d"
#define ELEMENT_MIN_WIDTH 1
#define ELEMENT_WIDTH_ADD 0
typedef struct {
unsigned rows;
unsigned cols;
MAT_ORDER_T order;
const char * name;
ELEMENT_T * data;
} MAT_T;
void matrix_init(MAT_T * m)
{
m->rows = 0;
m->cols = 0;
m->order = ROW_ORDER;
m->name = NULL;
m->data = NULL;
}
void matrix_alloc(MAT_T * m)
{
if (m->data == NULL) {
m->data = malloc(sizeof(ELEMENT_T) * m->rows * m->cols);
if (m->data == NULL) {
printf("Memory Allocation Error!\n");
exit(0);
}
}
}
void matrix_free(MAT_T * m)
{
if (m->data != NULL) free(m->data);
m->data = NULL;
}
#define ZDUFF \
switch (z % 8) {\
case 0: do { *c += *ta++ * *tb++;\
case 7: *c += *ta++ * *tb++;\
case 6: *c += *ta++ * *tb++;\
case 5: *c += *ta++ * *tb++;\
case 4: *c += *ta++ * *tb++;\
case 3: *c += *ta++ * *tb++;\
case 2: *c += *ta++ * *tb++;\
case 1: *c += *ta++ * *tb++;\
} while ((z-=8) > 0);\
}
#define YDUFF \
switch (y % 8) {\
case 0: do { ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 7: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 6: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 5: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 4: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 3: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 2: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
case 1: ta=a; *c=0; z=ma->cols; ZDUFF; ++c;\
} while ((y-=8) > 0);\
}
#define XDUFF \
switch (x % 4) {\
case 0: do { tb=b; y=mb->cols; YDUFF; a+=ma->cols;\
case 3: tb=b; y=mb->cols; YDUFF; a+=ma->cols;\
case 2: tb=b; y=mb->cols; YDUFF; a+=ma->cols;\
case 1: tb=b; y=mb->cols; YDUFF; a+=ma->cols;\
} while ((x-=4) > 0);\
}
void matrix_multiply(const MAT_T * ma, const MAT_T * mb,
MAT_T * mc)
{
const ELEMENT_T * a = ma->data, * ta;
const ELEMENT_T * b = mb->data, * tb;
ELEMENT_T * c;
int x, y, z;
mc->rows = ma->rows;
mc->cols = mb->cols;
matrix_alloc(mc);
c = mc->data;
x = ma->rows;
XDUFF;
}
void matrix_in(MAT_T * m, const char * name, unsigned order)
{
unsigned z;
unsigned datacount;
char buf[LONG_LINE_SIZE+1];
char format[SHORT_LINE_SIZE];
char * start;
int pos;
int lindex;
sprintf(format, "%s%%n", ELEMENT_SCAN_STRING);
matrix_init(m);
m->name = name;
m->order = order;
printf("Entering %s\n", m->name);
printf("Enter number of rows: ");
sscanf(fgets(buf, LONG_LINE_SIZE, stdin), "%u", &m->rows);
if (m->rows < 1) {
printf("Invalid number of rows!");
exit(0);
}
printf("Enter number of columns: ");
sscanf(fgets(buf, LONG_LINE_SIZE, stdin), "%u", &m->cols);
if (m->cols < 1) {
printf("Invalid number of columns!");
exit(0);
}
matrix_alloc(m);
for (z=0; z<m->rows; ++z) {
printf("Enter %u elements for Row %u :", m->cols, z);
fgets(buf, LONG_LINE_SIZE, stdin);
start = buf;
lindex = 0;
datacount = 0;
while (datacount != m->cols) {
if (sscanf(start, format,
&m->data[ (m->order==ROW_ORDER) ?
(z*m->cols+lindex) : (z+m->rows*lindex)],
&pos) != 1) {
printf("Invalid row data!");
exit(0);
}
else {
++lindex;
start += pos;
++datacount;
}
}
}
}
unsigned width(ELEMENT_T x)
{
unsigned w = ELEMENT_WIDTH_ADD;
if (x == 0) return 1;
if (x < 0) {
x *= -1;
++w;
}
while ((x > 1) || (x < -1)) {
x /= 10;
++w;
}
if (w < ELEMENT_MIN_WIDTH) w = ELEMENT_MIN_WIDTH;
return w;
}
void matrix_out(const MAT_T * m)
{
char format[SHORT_LINE_SIZE];
unsigned x, y, z, w, maxwidth=1;
for (z=0; z<(m->rows * m->cols); ++z) {
w = width(m->data[z]);
if (w > maxwidth) maxwidth = w;
}
sprintf(format, "%%%d%s ", maxwidth, ELEMENT_PRINT_STRING);
if (m->name != NULL) printf("%s\n", m->name);
for (y=0; y<m->rows; ++y) {
printf("[ ");
for (x=0; x<m->cols; ++x) {
printf(format,
m->data[ (m->order==ROW_ORDER) ?
(y*m->cols+x) : (y+m->rows*x)]
);
}
printf("]\n");
}
printf("\n");
}
int main(void)
{
MAT_T a, b, c;
matrix_in(&a, "Matrix A", ROW_ORDER);
matrix_in(&b, "Matrix B", COL_ORDER);
if (a.cols != b.rows) {
printf("Invalid Matrix sizes. Multiplication is not defined!\n");
exit(0);
}
matrix_init(&c);
c.name = "Product Matrix AB";
matrix_out(&a);
matrix_out(&b);
matrix_multiply(&a, &b, &c);
matrix_out(&c);
matrix_free(&a);
matrix_free(&b);
matrix_free(&c);
return 1;
}