我使用雅可比方法但通过手动输入来求解线性代数方程组Ax = b。我想分析大型系统求解器的性能。有没有任何方法可以生成矩阵A,即非奇异? 我在这里附上我的代码。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define TOL = 0.0001
void main()
{
int size,i,j,k = 0;
printf("\n enter the number of equations: ");
scanf("%d",&size);
double reci = 0.0;
double *x = (double *)malloc(size*sizeof(double));
double *x_old = (double *)malloc(size*sizeof(double));
double *b = (double *)malloc(size*sizeof(double));
double *coeffMat = (double *)malloc(size*size*sizeof(double));
printf("\n Enter the coefficient matrix: \n");
for(i = 0; i < size; i++)
{
for(j = 0; j < size; j++)
{
printf(" coeffMat[%d][%d] = ",i,j);
scanf("%lf",&coeffMat[i*size+j]);
printf("\n");
//coeffMat[i*size+j] = 1.0;
}
}
printf("\n Enter the b vector: \n");
for(i = 0; i < size; i++)
{
x[i] = 0.0;
printf(" b[%d] = ",i);
scanf("%lf",&b[i]);
}
double sum = 0.0;
while(k < size)
{
for(i = 0; i < size; i++)
{
x_old[i] = x[i];
}
for(i = 0; i < size; i++)
{
sum = 0.0;
for(j = 0; j < size; j++)
{
if(i != j)
{
sum += (coeffMat[i * size + j] * x_old[j] );
}
}
x[i] = (b[i] -sum) / coeffMat[i * size + i];
}
k = k+1;
}
printf("\n Solution is: ");
for(i = 0; i < size; i++)
{
printf(" x[%d] = %lf \n ",i,x[i]);
}
}
答案 0 :(得分:1)
Talonmies'评论提及http://www.eecs.berkeley.edu/Pubs/TechRpts/1991/CSD-91-658.pdf这可能是正确的方法(至少在原则上,完全通用)。
但是,您可能不处理&#34;非常大&#34;矩阵(例如,因为你的程序使用天真算法,并且因为你不在具有大量RAM的大型超级计算机上运行它)。因此,生成具有随机系数的矩阵并且之后测试它是非单数的天真方法可能就足够了。
非常大的矩阵会有数十亿个系数,你需要一个功能强大的超级计算机,例如:太字节的RAM。你可能没有,如果你这样做,你的程序可能会运行太久(你没有任何并行性),可能会给出非常错误的结果(阅读http://floating-point-gui.de/了解更多)所以你不在乎。
根据当前的硬件标准,百万系数(例如1024 * 1024)的矩阵被认为是 small (并且足以在当前的笔记本电脑或台式机上测试您的代码,甚至可以测试一些并行实现),并随机生成其中一些(并计算它们的行列式来测试它们不是单数)就足够了,而且很容易实现。您甚至可以使用某些外部工具生成它们和/或检查它们的规律性,例如: scilab,R,octave等。一旦您的程序计算出解决方案 x 0 ,您就可以使用某种工具(或写另一个程序)来计算 Ax 0 - b 并检查它是否非常接近0向量(在某些情况下你会感到失望或惊讶,因为{ {3}}问题)。
你需要一些足够好的round-off errors或许像pseudo random number generator一样简单,这被认为是近乎过时的(你应该找到并使用更好的东西);你可以使用一些随机源(例如Linux上的/dev/urandom
)播种它。
BTW,使用所有警告编译您的代码&amp;调试信息(例如gcc -Wall -Wextra -g
)。您的#define TOL = 0.0001
可能不对(应为#define TOL 0.0001
或const double tol = 0.0001;
)。使用调试器(gdb
)&amp; drand48(3)。在进行基准测试时添加优化(-O2 -mcpu=native
)。阅读每个使用过的函数的文档,特别是来自valgrind的函数。检查scanf
的结果计数...在C99中,你不应该转换malloc
的结果,但是你忘了测试它的失败,所以代码:
double *b = malloc(size*sizeof(double));
if (!b) {perror("malloc b"); exit(EXIT_FAILURE); };
您宁愿结束,而不是开始使用printf
\n
控制字符串,因为stdout
通常(并不总是!)行缓冲。另请参阅fflush
。
您可能还应该阅读一些基本的线性代数教科书......
请注意,实际编写强大而有效的程序来反转矩阵或解决线性系统是一项困难的艺术(我根本不知道:它有编程问题,算法问题和数学问题;阅读一些{ {3}}书)。你仍然可以获得博士学位并一生都在努力。请理解您需要<stdio.h>
(或许多其他内容)。
答案 1 :(得分:1)
这一点都是希思罗宾逊,但这就是我用过的东西。我不知道这些矩阵是如何“随机”的,特别是我不知道它们遵循什么样的分布。
想法是生成矩阵的SVD。 (在下面称为A,并假设为nxn)。
将A初始化为全0
然后生成n个正数,并在A的对角线上放置随机符号。我发现能够控制这些正数中最大值与最小值的比值是有用的。该比率将是矩阵的条件数。
然后重复n次:生成随机n向量f,并在左侧乘以Householder反射器I - 2 * f * f'/(f'* f)。注意,这可以比通过形成反射器矩阵和进行正常乘法更有效地完成;确实很容易编写一个例程,给定f和A将更新A。
重复上述步骤,但在右侧相乘。
至于生成测试数据,一种简单的方法是选择x0然后生成b = A * x0。不要指望从你的求解器中得到完全的x0;即使表现非常好,你也会发现随着条件数量的增加,误差会变大。