高斯赛德尔(C中的特定方程求解器)

时间:2014-12-30 20:10:49

标签: c

在此尝试之前发布一个格式错误的问题的道歉。

我试图让高斯赛德尔方法在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

有什么建议吗?

2 个答案:

答案 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;
            }
        }
    }
}