对于矩阵乘法器C程序,如何获得未知矩阵的正确维数



所以我的尝试是创建一个程序,自动从.txt文件中获取两个矩阵的大小并将它们相乘。我可以制作给定大小的程序,所以就其本身而言,我只对列和行的计数有问题。

输入类似(MxN矩阵(:

1 2 3 4

1 2 3 4

1 2 3 4

具体来说,这是我到目前为止的程序(我认为代码的开头是相关的(:

#include <stdio.h>
#include <stdlib.h>
struct mat1
{
int cols;
int rows;
};
struct mat2
{
int cols;
int rows;
};
struct mat1 dim1(const char* file)
{
struct mat1 m1;
int rows = 0;
int cols = 0;
char c;
FILE *f = fopen(file, "r+");
while((c = fgetc(f) != EOF))
{
if(c != 'n' && rows == 0)
{
cols++;
}
else if(c == 'n')
rows++;
}
rows++;
return m1;
}
struct mat2 dim2(const char* file)
{
struct mat2 m2;
int rows = 0;
int cols = 0;
char c;
FILE *f = fopen(file, "r+");
while((c = fgetc(f) != EOF))
{
if(c != 'n' && rows == 0)
{
cols++;
}
else if(c == 'n')
rows++;
}
rows++;
return m2;
}

double* alloc_matrix(int cols, int rows) {
double* m = (double*)malloc(cols * rows * sizeof(double));
if (m == 0) {
printf("Memory allocation error.n");
exit(-1);
}
return m;
}
void read_matrix(FILE* f, double* m, int cols, int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
fscanf(f, "%lf", &m[i * cols + j]);
}
}
}
void multiplication(double* m1, double* m2, double* m3, int cols, int rows) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
m3[i * cols +j]=0;
for(int k = 0; k < cols; k++) {
m3[i * cols +j]+=m1[i * cols +k]*m2[k * cols +j];
}
}
}
}
void write_matrix(double* m, int cols, int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%f ", m[i * cols + j]);
}
printf("n");
}
}

int main(int argc, char* argv[])
{
char* matrix1 = argv[1];
char* matrix2 = argv[2];
if (argc < 3) {
printf("Not enough arguments.n");
exit(-1);
}
struct mat1 m1 = dim1(matrix1);
struct mat2 m2 = dim2(matrix2);
printf(" %d   %d n", m1.cols, m1.rows);
printf(" %d   %d n", m2.cols, m2.rows);
int c1 = m1.cols;
int r1 = m1.rows;
int c2 = m2.cols;
int r2 = m2.rows;
if (r1!=c2)
{
printf("Matrixes are not suitable for multiplication. n");
exit(-1);
}
double* mtx1 = alloc_matrix(c1, r1);
double* mtx2 = alloc_matrix(c2, r2);
FILE* f1 = fopen(matrix1, "r");
if (f1 == 0)
{
printf("Cannot open file %s.", argv[1]);
exit(-1);
}
FILE* f2 = fopen(matrix2, "r");
if (f1 == 0)
{
printf("Cannot open file %s.", argv[1]);
exit(-1);
}
read_matrix(f1, mtx1, c1, r1);
read_matrix(f2, mtx2, c2, r2);
double* mtx3 = alloc_matrix(c1, r2);
multiplication(mtx1, mtx2, mtx3, c1, r2);
write_matrix(mtx3, c1, r2);
free(mtx1);
free(mtx2);
free(mtx3);
fclose(f1);
fclose(f2);
return 0;
}

当我试用2个3x3矩阵时,输出:

6422164 4199040(来自我设置用于检查尺寸的2个printf(((。

6422164 4199040

矩阵不适合相乘(无关(

所以基本上它不使用3x3。

我搞不清楚问题出在哪里。

前面是我的热门评论。

我必须重构dim来处理任意大的矩阵,所以我必须逐个字符扫描文件的第一行,计算空白字符串(这产生列数-1(。它处理/剥离前导/尾随空白[格式错误]

我有dim,然后倒带文件,并使用fscanfrealloc动态创建矩阵。


以下是工作代码[请原谅免费的样式清理]:

#include <stdio.h>
#include <stdlib.h>
struct mat {
int cols;
int rows;
double *m;
};
// size and read in matrix
struct mat
dim(const char *file)
{
struct mat m;
int rows = 0;
int cols = 0;
int maxcnt;
int curcnt;
int ret;
int c;
int c2;
FILE *f = fopen(file, "r+");
// strip leading whitespace [if any] off first line
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == 'n')
break;
if (c != ' ')
break;
}
// scan first line and count columns (number of space separaters)
while (1) {
c2 = ' ';
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == 'n') {
if (c2 != ' ')
++cols;
break;
}
if (c == ' ') {
if (c != c2)
++cols;
break;
}
c2 = c;
}
if (c == 'n')
break;
}
// convert number of whitespace separaters into number of columns
if (cols > 0)
++cols;
rewind(f);
m.rows = 0;
m.cols = cols;
m.m = NULL;
curcnt = 0;
maxcnt = 0;
while (1) {
if (curcnt >= maxcnt) {
maxcnt += m.cols * 100;
double *tmp = realloc(m.m,sizeof(double) * maxcnt);
if (tmp == NULL) {
printf("dim: realloc failuren");
exit(1);
}
m.m = tmp;
}
ret = 0;
for (int idx = 0;  idx < cols;  ++idx, ++curcnt) {
ret = fscanf(f, "%lf", &m.m[curcnt]);
if (ret != 1)
break;
}
if (ret != 1)
break;
rows += 1;
}
fclose(f);
m.rows = rows;
// trim matrix to actual size;
m.m = realloc(m.m,sizeof(double) * rows * cols);
return m;
}
double *
alloc_matrix(int cols, int rows)
{
double *m = (double *) malloc(cols * rows * sizeof(double));
if (m == 0) {
printf("Memory allocation error.n");
exit(-1);
}
return m;
}
void
multiplication(double *m1, double *m2, double *m3, int cols, int rows)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m3[i * cols + j] = 0;
for (int k = 0; k < cols; k++) {
m3[i * cols + j] += m1[i * cols + k] * m2[k * cols + j];
}
}
}
}
void
write_matrix(double *m, int cols, int rows)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%f ", m[i * cols + j]);
}
printf("n");
}
}
int
main(int argc, char *argv[])
{
if (argc < 3) {
printf("Not enough arguments.n");
exit(1);
}
struct mat m1 = dim(argv[1]);
struct mat m2 = dim(argv[2]);
printf(" %d   %d n", m1.cols, m1.rows);
printf(" %d   %d n", m2.cols, m2.rows);
int c1 = m1.cols;
int r1 = m1.rows;
int c2 = m2.cols;
int r2 = m2.rows;
if (r1 != c2) {
printf("Matrixes are not suitable for multiplication.n");
exit(-1);
}
double *mtx3 = alloc_matrix(c1, r2);
multiplication(m1.m, m2.m, mtx3, c1, r2);
write_matrix(mtx3, c1, r2);
free(m1.m);
free(m2.m);
free(mtx3);
return 0;
}

这是我使用的两个测试文件。请注意,尽管您看不到它,但第一行有尾随的空白[作为测试]:

这是m1.txt:

1 2  3  4
5 6 7  8
9 10  11  12

这是第二个文件:

1  2  3
4 5 6
7 8 9
10 11 12

这是程序输出:

4   3
3   4
38.000000 44.000000 202.000000 232.000000
98.000000 116.000000 438.000000 504.000000
158.000000 188.000000 674.000000 776.000000
9.000000 10.000000 87.000000 100.000000

更新:

这里有一个可变的dim函数,它将第一行的逐字符扫描替换为换行扫描[以获得行长度],然后是缓冲区的mallocfgets,然后在strtok上循环以计数行中的非空格字符串(即列数(:

// size and read in matrix
struct mat
dim(const char *file)
{
struct mat m;
int rows = 0;
int cols = 0;
int maxcnt;
int curcnt;
int ret;
char *buf;
char *bp;
char *tok;
int c;
int c2;
FILE *f = fopen(file, "r+");
// count number of chars in first line of the file
curcnt = 0;
while (1) {
c = fgetc(f);
if (c == EOF)
break;
++curcnt;
if (c == 'n')
break;
}
++curcnt;
buf = malloc(curcnt);
rewind(f);
fgets(buf,curcnt,f);
cols = 0;
bp = buf;
while (1) {
tok = strtok(bp," n");
if (tok == NULL)
break;
++cols;
bp = NULL;
}
free(buf);
rewind(f);
m.rows = 0;
m.cols = cols;
m.m = NULL;
curcnt = 0;
maxcnt = 0;
while (1) {
if (curcnt >= maxcnt) {
maxcnt += m.cols * 100;
double *tmp = realloc(m.m,sizeof(double) * maxcnt);
if (tmp == NULL) {
printf("dim: realloc failuren");
exit(1);
}
m.m = tmp;
}
ret = 0;
for (int idx = 0;  idx < cols;  ++idx, ++curcnt) {
ret = fscanf(f, "%lf", &m.m[curcnt]);
if (ret != 1)
break;
}
if (ret != 1)
break;
rows += 1;
}
fclose(f);
m.rows = rows;
// trim matrix to actual size;
m.m = realloc(m.m,sizeof(double) * rows * cols);
return m;
}

更新#2:

我不喜欢这两种获取列数的解决方案,所以这里有一种更干净的解决方案与第一种一样快,但更简单、不那么麻烦:

// scan first line and count columns
int
colcalc(FILE *f)
{
int c;
int noncur;
int nonprev = 0;
int cols = 0;
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == 'n')
break;
// only count non-whitespace chars
switch (c) {
case ' ':
case 't':
noncur = 0;
break;
default:
noncur = 1;
break;
}
// column starts on _first_ char in word
if (noncur)
cols += (noncur != nonprev);
nonprev = noncur;
}
rewind(f);
return cols;
}

更新#3:

我试过你之前的两种方法,效果非常顺利!再次感谢!以及你关于用更少的变量和东西让我的程序更简单的评论!

不客气!

我的编码风格/方法来自一本[非常]古老的书:Kernighan和Plauger的《编程风格的元素》。

这本书中的例子是用Fortran编写的,但格言与Steve McConnell的"Code Complete"不相上下。

摘自第7章【效率和仪器】:

  • 先做对,然后再做快
  • 当你加快速度时,保持正确
  • 在你加快速度之前先把它弄清楚
  • 不要为了"效率"上的小收获而牺牲清晰度
  • 不要过度使用代码;取而代之的是重组
  • 确保特殊情况真的很特别
  • 保持简单,让它更快
  • 不要为了更快而篡改代码——找一个更好的算法
  • 为您的程序提供工具。在做出"效率"改变之前进行测量

相关内容

最新更新