在此尝试之前发布一个格式错误的问题的道歉。
我试图让高斯赛德尔方法在C中工作,检查它比更高级别的解释语言(即python)快多少,但我对结果有一些问题我得到了。
我的输入矩阵是
所以我相信它应该收敛。
问题试图解决" Ax = b" ,
(其中' A' =' a [] []',' b' =' b []'和' x' =' x []')
最后一个数组' check []'是通过' a'之间的点积获得的。和' x'看它是否返回接近' b'。
以下代码完全可执行。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void)
{
int i=0,j=0;
int num=0;
double h = 1.0/(3+1);
double h2 = pow(h,2);
double w=1.5, sum=0.0;
long double x[9],y[9], check[9];
long double tol = pow(10, -10);
long double a[9][9] = {{-4, 1, 0, 1, 0, 0, 0, 0, 0} ,
{1, -4, 1, 0, 1, 0, 0, 0, 0} ,
{0, 1, -4, 0, 0, 1, 0, 0, 0} ,
{1, 0, 0, -4, 1, 0, 1, 0, 0} ,
{0, 1, 0, 1, -4, 1, 0, 1, 0} ,
{0, 0, 1, 0, 1, -4, 0, 0, 1} ,
{0, 0, 0, 1, 0, 0, -4, 1, 0} ,
{0, 0, 0, 0, 1, 0, 1, -4, 1} ,
{0, 0, 0, 0, 0, 1, 0, 1, -4}};
long double b[9] = {0.000000,
0.000000,
0.000000,
0.000000,
0.125000,
0.000000,
0.000000,
0.000000,
0.000000 };
for(i=0;i<9;i++){ // initialise the arrays to 0
x[i]=0;
y[i]=2*tol;
}
for(i=0;i<9;i++){ // prints 'a' matrix, to check if its right
for(j=0;j<9;j++){
printf("a[%d][%d] = %LF ",i,j,a[i][j]);
}
printf("\n" );
}
printf("\n\n");
for(i=0;i<9;i++){ // prints b matrix
printf("b[%d] = %LF \n",i,b[i]);
}
do{ // the Gauss seidel Solver
for(i =0;i<9;i++){
for(j=0; j<9; j++){
if(i!=j){
sum += a[i][j]*x[j];
}
x[i] = (w/a[i][i])* (b[i] - sum + a[i][i]*x[i]) + (1-w)*x[i];
}
}
num=num+1;
}while (fabs(y[i]-x[i])>tol);
printf("\n\n\n");
for(i=0;i<9;i++){ // Prints the solution X
printf("x[%d] = %LF \n",i,x[i]);
}
printf("\n\n");
for(i=0;i<9;i++){ // Ititialises matrix
check[i]=0;
}
for (i = 0; i < 9; i++){ // performs a dot product of
// 'a' and 'x', to see if we get
// 'b' as the result
for(j = 0; j< 9; j++){
check[i]+= a[i][j] * x[j];
}
check[i] = check[i]/h2; // the 'b' matrix was multiplied by h2,
// hence to get it back, a division is necessary
printf("check[%d] = %LF\n",i,check[i]);
}
printf("num=%d\n",num );
return 0;
}
输出,即&#39; x&#39;我得到的是:
x[0] = -0.000000
x[1] = -0.000000
x[2] = -0.000000
x[3] = -0.000000
x[4] = -0.421875
x[5] = -0.791016
x[6] = -1.423828
x[7] = -3.816650
x[8] = -11.702087
和&#39;检查&#39;的输出我得到的是:
check[0] = 0.000000
check[1] = -4.500000
check[2] = -5.625000
check[3] = -14.625000
check[4] = -10.968750
check[5] = -42.328125
check[6] = 17.156250
check[7] = 18.421875
check[8] = 212.343750
理想情况下,如果一切正常,请检查[4]应输出2(输出&#39;检查&#39;时代码中的注释中给出的原因),并且每个其他检查元素应为0
有什么建议吗?
答案 0 :(得分:4)
sum
应该在for循环内重新初始化为0,并且方程式不正确。您在python实现中使用的等式假定已添加a[i][i]*x[i]
以生成完整的点积,他们使用numpy
来获取点积而不是循环,因此他们没有机会i != j
1}}。此外,我不确定该实现中的等式是高斯赛德尔方法,由于w
和(1 - w)
,它看起来更像是连续松弛。无论如何,这是我修改过的解决方案。我使用错误检查收敛,| Ax - b | &LT;所有参赛作品的费用。 for循环被分成两个作为小优化。 a[i][i] * x[i]
被添加到sum
以获取错误检查中(Ax) i 的当前值。
int converged;
do {
converged = 1;
for (i = 0; i < 9; i++) {
sum = 0;
for (j = 0; j < i; j++) {
sum += a[i][j] * x[j];
}
for (j = i + 1; j < 9; j++) {
sum += a[i][j] * x[j];
}
x[i] += w * ((b[i] - sum) / a[i][i] - x[i]);
if (fabs(sum + a[i][i] * x[i] - b[i]) > tol) {
converged = 0;
}
}
} while (!converged);
给出输出:
x[0] = -0.007812
x[1] = -0.015625
x[2] = -0.007812
x[3] = -0.015625
x[4] = -0.046875
x[5] = -0.015625
x[6] = -0.007812
x[7] = -0.015625
x[8] = -0.007813
check[0] = 0.000000
check[1] = -0.000000
check[2] = -0.000000
check[3] = -0.000000
check[4] = 2.000000
check[5] = 0.000000
check[6] = -0.000000
check[7] = 0.000000
check[8] = 0.000000
num=31
答案 1 :(得分:1)
为了那些跟随在家的人的利益。我建议你阅读wikipedia article on Gauss-Seigel。我将尝试解释算法正在做什么,并提供实现该算法的C代码。
维基百科页面中的Python示例将此简单示例用于矩阵A和B
| 10 -1 2 0 | | 6 |
A = | -1 11 -1 3 | B = | 25 |
| 2 -1 10 -1 | | -11 |
| 0 3 -1 8 | | 8 |
那些矩阵代表以下方程组
10*x1 - x2 + 2*x3 = 6
-x1 + 11*x2 - x3 + 3*x4 = 25
2*x1 - x2 + 10*x3 - x4 = -11
3*x2 - x3 + 8*x4 = 15
我们试图用Gauss-Seigel找到的解决方案是
x1=1 x2=2 x3= -1 x4=1
那么算法如何工作?那么首先要大胆猜测答案,例如
x1=0 x2=0 x3=0 x4=0
然后将这些猜测插入方程式并尝试改进猜测。具体来说,将x2,x3,x4的值插入第一个等式中,然后计算x1的新值。
10*x1 - 0 + 0 = 6 ==> x1 = 6/10 = 0.6
然后将x1的 new 值和x3,x4的旧值插入第二个等式以获得x2的改进猜测
-0.6 + 11*x2 - 0 + 0 = 25 ==> 11*x2 = 25.6 ==> x2 = 2.327273
对于x3和x4
2*0.6 - 2.327273 + 10*x3 - 0 = -11 ==> 10*x3 = -9.872727 ==> x3 = -0.987273
3*2.327273 + 0.987273 + 8*x4 = 15 ==> 8*x4 = 7.030908 ==> x4 = 0.878864
因此,在Gauss-Seigel的一次迭代之后,对答案的改进猜测是
x1=0.6 x2=2.327273 x3= -0.987273 x4=0.878864
算法一直持续到解决方案收敛或超过最大迭代次数为止。
以下是C中的代码。计数器k
限制了迭代次数(以防解决方案不收敛)。通过在跳过X[i]
的同时评估每个方程来应用Gauss-Seidel方法。然后计算X[i]
的新值。代码显示X[]
的新值,并通过评估每个等式并验证总和是否在B[i]
的epsilon内来检查答案是否足够好。
#include <stdio.h>
#include <math.h>
#define SIZE 4
double A[SIZE][SIZE] = {
{ 10, -1, 2, 0 },
{ -1, 11, -1, 3 },
{ 2, -1, 10, -1 },
{ 0, 3, -1, 8 }
};
double B[SIZE] = { 6, 25, -11, 15 };
double X[SIZE] = { 0, 0, 0, 0 };
int main( void )
{
int i, j, k, done;
double sum;
done = 0;
for ( k = 0; k < 100 && !done; k++ )
{
// perform the next iteration of Gauss-Seidel
for ( i = 0; i < SIZE; i++ )
{
sum = 0;
for ( j = 0; j < SIZE; j++ )
if ( j != i )
sum += A[i][j] * X[j];
X[i] = (B[i] - sum) / A[i][i];
}
// print the k'th iteration of X[]
printf( "%2d --", k );
for ( i = 0; i < SIZE; i++ )
printf( " %lf", X[i] );
printf( "\n" );
// check for convergence
done = 1;
for ( i = 0; i < SIZE; i++ )
{
sum = 0;
for ( j = 0; j < SIZE; j++ )
sum += A[i][j] * X[j];
if ( fabs( B[i] - sum ) > 1e-6 )
{
done = 0;
break;
}
}
}
}