从文本文件中读取复杂矩阵



我在试图从c文本文件中读取复杂矩阵时遇到了很多麻烦。该文本文件的格式为(%le%+lej)。使用的测试矩阵为:

(0.000000000000000000e+00+0.000000000000000000e+00j)  (0.000000000000000000e+00+1.000000000000000056e-01j)  (0.000000000000000000e+00+2.000000000000000111e-01j)  (0.000000000000000000e+00+3.000000000000000444e-01j)
(1.100000000000000089e+00+0.000000000000000000e+00j)  (1.100000000000000089e+00+1.000000000000000056e-01j)  (1.100000000000000089e+00+2.000000000000000111e-01j)  (1.100000000000000089e+00+3.000000000000000444e-01j)
(2.200000000000000178e+00+0.000000000000000000e+00j)  (2.200000000000000178e+00+1.000000000000000056e-01j)  (2.200000000000000178e+00+2.000000000000000111e-01j)  (2.200000000000000178e+00+3.000000000000000444e-01j)

我花了将近两天的时间试图让这个工作。所以我想一个简单,容易调试的解决方案,如果这样的事情存在。

我的简化尝试:

#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
int main(void)
{
char fname[] = "test_matrix.dat";
int m = 3;
int n = 4;
complex double * matrix = calloc(m * n, sizeof(complex double));
FILE * ifile = fopen(fname, "r");
int i, j, info;
double zreal, zimag;
for(i = 0; i < m; i++)
{
for(j = 0; j < n; j++)
{
info = fscanf(ifile, "(%le%lej)", &zreal, &zimag);
// The following doesn't work either.
// info = fscanf(ifile, "(%le", &zreal);
// info += fscanf(ifile, "%lej)", &zimag);
if(info != 2)
{
fclose(ifile);
fprintf(stderr, "Wrong input format, info = %dn", info);
exit(EXIT_FAILURE);
}
*(matrix + i + j*m) = zreal + I*zimag;
// printf("%d ", info); This gives all zeroes
printf("%6.1e%+7.1ej ", zreal, zimag);
}
printf("n");
}
fclose(ifile);
free(matrix);
return(0);
}

我也试着不把额外的格式化的东西在fscanf,相反,我试着循环fgetc,直到我读(,然后做两个fscanfs,但它很快变得过于复杂和难以调试,仍然没有能够得到那工作。因此,任何帮助都将不胜感激。

编辑:这与问题无关,但只是为了澄清我使用列主格式,因为它必须与blas/lapack一起使用。

fscanf格式不正确:

info = fscanf(ifile, " (%le+%lej)", &zreal, &zimag);

既然你要求,我想通过提供一个完整的工作示例来补充Fryz的答案:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <complex.h>
int main(void)
{
const char *filename = "test_matrix.dat";
FILE *file = fopen(filename, "r");
if (!file) {
perror("Could not open file");
return 1;
}
const size_t nrows = 3;
const size_t ncols = 4;
complex double *matrix = malloc(nrows * ncols * sizeof(*matrix));
if (!matrix) {
printf("Internal errorn");
fclose(file);
return 1;
}
double zreal, zimag;
for (size_t i = 0; i < nrows; ++i) {
for (size_t j = 0; j < ncols; ++j) {
if (fscanf(file, " (%le+%lej)", &zreal, &zimag) != 2) {
printf("%zu::%zu: Wrong formatn", i, j);
continue;
}
matrix[i*ncols+j] = zreal + I * zimag;
printf("(%.18le+%1.18lej) ", zreal, zimag);
}
printf("n");
}
free(matrix);
fclose(file);
}

输出:

(0.000000000000000000e+00+0.000000000000000000e+00j) (0.000000000000000000e+00+1.000000000000000056e-01j) (0.000000000000000000e+00+2.000000000000000111e-01j) (0.000000000000000000e+00+3.000000000000000444e-01j)
(1.100000000000000089e+00+0.000000000000000000e+00j) (1.100000000000000089e+00+1.000000000000000056e-01j) (1.100000000000000089e+00+2.000000000000000111e-01j) (1.100000000000000089e+00+3.000000000000000444e-01j)
(2.200000000000000178e+00+0.000000000000000000e+00j) (2.200000000000000178e+00+1.000000000000000056e-01j) (2.200000000000000178e+00+2.000000000000000111e-01j) (2.200000000000000178e+00+3.000000000000000444e-01j)

注意事项:

  • 总是检查C标准库函数的返回值。
  • 当一个变量的值不会被改变时,使用const
  • 索引的合适类型是size_t,而不是int
  • 关闭你的文件句柄,当你用完它们时释放你分配的内存。

以下代码在我的计算机上运行成功,输入如下:

#include <stdio.h>
int main()
{
double x, y;
int res;
while ((res = fscanf(stdin, "(%lg%lgj)", &x, &y)) == 2) {
printf("(%g, %g)", x, y);
}
printf("res == %dn", res);
}

和以下输入:

$ a.out
(3-5j)(2-8j)(-6+3j)                    <-- input
(3, -5)(2, -8)(-6, 3)res == 0          <-- output
$ _

正如您可能猜到的那样,只要我按下返回键,输入不匹配,并且我读取三个有效的复数,之后没有任何匹配(fscanf()获得n字符,并且不读取任何内容,向while循环返回0。我打印了函数的结果,看看为什么它失败了。在输入之间,您应该自己处理空白(当您扫描n时也要区分)是我的建议。

一种更好的格式是扫描两个数字来表示矩阵维度,然后扫描rows*cols对数字来表示矩阵内容,它们之间用任何形式的空格分隔。例如

2 2
1 0 0 0
0 0 1 0

将导致从输入文件中读取单位矩阵。

对于更复杂的阅读器,您需要从flex(1)和/或bison(1)工具中获得帮助,这些工具允许您处理空白,甚至注释或嵌套括号!!:)编写这些工具是为了帮助您对复杂语言(如C或pascal)进行全面解析。

最新更新