LU分解算法的C语言实现(数值分析经典算法)

LU分解算法的C语言实现

  • 算法理论
  • 算法对应的实验要求
    • 实验要求
    • 实验要求解析
        • Step1:定义变量
        • Step2:对L矩阵的第一列进行先赋值
        • Step3:对U的第r行和L的第r列进行赋值(r=2,3,...,n)
        • Step4:判断矩阵A是否能进行LU分解
        • Step5:由Ly=b求解出y数组
        • Step6:由Ux=y求解出x数组
  • 代码实现
    • 输入输出检测

算法理论

A = L U A=LU A=LU分解算法:
1. u 1 i = a 1 i , ( i = 1 , 2 , ⋯   , n ) ; l i 1 = a i 1 / u 11 , ( i = 2 , 3 , ⋯   , n ) 1. u_{1i}=a_{1i} ,(i=1,2,\cdots,n) ; l_{i1}=a_{i1}/u_{11} ,(i=2,3,\cdots,n) 1.u1i=a1i,(i=1,2,,n);li1=ai1/u11,(i=2,3,,n)
计算 U U U的第 r r r行, L L L的第 r r r列元素 ( r = 2 , 3 , ⋯   , n ) (r=2,3,\cdots,n) (r=2,3,,n):
2. u r i = a r i − ∑ k = 1 r − 1 l r k u k r , ( i = r , r + 1 , ⋯   , n ) 2. u_{ri}=a_{ri}-\sum_{k=1}^{r-1}l_{rk}u_{kr},(i=r,r+1,\cdots,n) 2.uri=arik=1r1lrkukr,(i=r,r+1,,n)
3. l i r = ( a i r − ∑ k = 1 r − 1 l i k u k r ) / u r r , ( i = r + 1 , ⋯   , n , 且 r ≠ n ) 3. l_{ir}=(a_{ir}-\sum_{k=1}^{r-1}l_{ik}u_{kr})/u_{rr},(i=r+1,\cdots,n,且r\neq n) 3.lir=(airk=1r1likukr)/urr,(i=r+1,,n,r̸=n)
求解 L y = b , U x = y Ly=b,Ux=y Ly=b,Ux=y的计算公式:
4. y 1 = b 1 ; y i = b i − ∑ k = 1 i − 1 l i k y k , ( i = 2 , 3 , ⋯   , n ) 4. y1=b1;y_i=b_i-\sum_{k=1}^{i-1}l_{ik}y_k,(i=2,3,\cdots,n) 4.y1=b1;yi=bik=1i1likyk,(i=2,3,,n)
5. x n = y n / u n n ; x i = ( y i − ∑ k = i + 1 n u i k x k ) / u i i , ( i = n − 1 , n − 2 , ⋯   , 1 ) 5. x_n=y_n/u_{nn};x_i=(y_i-\sum_{k=i+1}^{n}u_{ik}x_k)/u_{ii},(i=n-1,n-2,\cdots,1) 5.xn=yn/unn;xi=(yik=i+1nuikxk)/uii,(i=n1,n2,,1)
其中值得注意的是:LU分解所用到的数学知识很基础并没有太大难度,只不过是矩阵乘法的知识以及两个矩阵相等时其对应元素也相等的知识。

算法对应的实验要求

实验要求

用LU分解算法求解给定的线性方程组 A x ⃗ = b ⃗ A\vec{x}=\vec{b} Ax =b ,其中函数接口定义为:

bool Direct( int n, double a[][MAX_SIZE], double b[] )

D i r e c t Direct Direct的接口定义中, n n n为矩阵 a a a的维数,MAX_SIZE是由裁判程序定义的矩阵最大维数, b ⃗ \vec{b} b 是方程组中的常向量,求得的解将存储在 b ⃗ \vec{b} b 中返回。本题目要求先用杜利特尔分解,再求解两个三角型方程组。函数返回布尔型值,当求解成功时返回TRUE,否则返回FALSE。
其中裁判程序的主函数为:

int main()
{
  int n, i, j;
  double a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE];
  while ( scanf("%d", &n) != EOF ) { /* 读取裁判测试用例 */
    for ( i=0; i<n; i++ ) {
      for ( j=0; j<n; j++ )
        scanf("%lf", &a[i][j]);
      scanf("%lf", &b[i]);
    }
    /*--- 输出直接法的解 ---*/
    if ( Direct(n, a, b) ) {
      printf("Result of direct method:\n");
      for ( j=0; j<n; j++ )
        printf("%.8lf\n", b[j]);
    }
    else
      printf("Doolittle factorization failed.\n");
    printf("\n");
  }
  return 0;
}

实验要求解析

L U LU LU分解实验中最重要的函数为 D i r e c t Direct Direct函数,下面将给出实现 D i r e c t Direct Direct函数的步骤。

Step1:定义变量

由于 D i r e c t Direct Direct函数返回 b o o l bool bool值,所以首先定义一个 b o o l bool bool类型的变量“ f l a g flag flag”并初始化为 t r u e true true,作为判断矩阵A是否能进行 L U LU LU分解的标志;其次,由于对 A A A进行 L U LU LU分解的矩阵 L L L为单位下三角矩阵, U U U为上三角矩阵,所以LU可以同时存在并覆盖原始的A矩阵,故无需创建新的矩阵 L L L U U U;最后需建立一个 d o u b l e double double类型的y数组存放 L y ⃗ = b ⃗ L\vec{y}=\vec{b} Ly =b y ⃗ \vec{y} y 的值。

Step2:对L矩阵的第一列进行先赋值

由于后续的计算需要用到L矩阵的第一列,故需先进行赋值;而由于U矩阵的第一行与A矩阵的第一行相同,故可以不做赋值处理。

Step3:对U的第r行和L的第r列进行赋值(r=2,3,…,n)

此处的赋值操作与“算法理论”部分介绍的思想一致。

Step4:判断矩阵A是否能进行LU分解

由于只有非奇异的矩阵 A A A才能进行 L U LU LU分解,但在实验过程中,计算矩阵 A A A的行列式是否非0或判断矩阵 A A A的顺序主子式是否都大于0相对而言都比较困难,所以要采取其他方式进行判断。
在求解 l i r l_{ir} lir的过程中,由于
l i r = ( a i r − ∑ k = 1 r − 1 l i k u k r ) / u r r , ( i = r + 1 , ⋯   , n , 且 r ≠ n ) l_{ir}=(a_{ir}-\sum_{k=1}^{r-1}l_{ik}u_{kr})/u_{rr},(i=r+1,\cdots,n,且r\neq n) lir=(airk=1r1likukr)/urr,(i=r+1,,n,r̸=n)
故只需最后对 u r r u_{rr} urr做出判断即可。当 u r r = 0 u_{rr}=0 urr=0时将 f l a g flag flag置为 f a l s e false false,并直接返回 f l a g flag flag,不再进行后续的“Step5”和“Step6”操作。

Step5:由Ly=b求解出y数组

Step6:由Ux=y求解出x数组

由于求解出的 x ⃗ \vec{x} x ,可以存储在b数组中,所以在“Step1:定义变量”中并未定义x数组,求出的解 x ⃗ \vec{x} x 即全部存储在b数组中。

代码实现

#include<stdio.h>
#include<math.h>
#include<stdbool.h>
#define MAX_SIZE 100 /* 矩阵最大维数 */
#define ZERO 0.000000001 /* 当一个正数小于ZERO就认为该数是0 */

bool Direct( int n, double a[][MAX_SIZE], double b[] )
{
    bool flag = true;
    double y[n];
    int r;
    int i;
    int k;
    double sum_u, sum_l;
    for(r=1;r<n;r++)
        a[r][0] = a[r][0]/a[0][0];
    for(r=1;r<n;r++)
    {
        for(i=r;i<n;i++)
        {
            sum_u = 0;
            for(k=0;k<r;k++)
                sum_u += a[r][k]*a[k][i];
            a[r][i] = a[r][i]-sum_u;
        }
        for(i=r+1;i<n&&r!=n-1;i++)
        {
            sum_l = 0;
            for(k=0;k<r;k++)
                sum_l += a[i][k]*a[k][r];
            a[i][r] = (a[i][r]-sum_l)/a[r][r];
        }
    }
    //--------------------------------------------------------------------------//
    for(r=0;r<n;r++)
    {
        if(a[r][r]==0) //等价于判断矩阵的顺序主子式是否为0
        {
            flag = false;
            return flag;
        }
    }
    //--------------------------------------------------------------------------//
    //--------------------------------------------------------------------------//
    y[0] = b[0];
    double sum;
    for(i=1;i<n;i++)
    {
        sum = 0;
        for(k=0;k<i;k++)
            sum += a[i][k]*y[k];
        y[i] = b[i]-sum;
    }
    //--------------------------------------------------------------------------//
    //--------------------------------------------------------------------------//
    b[n-1] = y[n-1]/a[n-1][n-1];
    for(i=n-2;i>=0;i--)
    {
        sum = 0;
        for(k=i+1;k<n;k++)
            sum += a[i][k]*b[k];
        b[i] = (y[i]-sum)/a[i][i];
    }
    return flag;
}



int main()
{
    int n, i, j;
    double a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE];

    while ( scanf("%d", &n) != EOF ) { /* 读取裁判测试用例 */
        for ( i=0; i<n; i++ )
        {
            for ( j=0; j<n; j++ )
                scanf("%lf", &a[i][j]);
            scanf("%lf", &b[i]);
        }
    /*--- 输出直接法的解 ---*/
    if ( Direct(n, a, b) )
    {
        printf("Result of direct method:\n");
            for ( j=0; j<n; j++ )
                printf("%.8lf\n", b[j]);
    }
    else
        printf("Doolittle factorization failed.\n");
    printf("\n");
  }
  return 0;
}

输入输出检测

Input: 
6
4 -1 0 -1 0 0 0
-1 4 -1 0 -1 0 5
0 -1 4 0 0 -1 0
-1 0 0 4 -1 0 6
0 -1 0 -1 4 -1 -2
0 0 -1 0 -1 4 6
Output: 
Result of direct method:
1.00000000
2.00000000
1.00000000
2.00000000
1.00000000
2.00000000
//--------------------------------//
Input:
3
3 -1 0 1
3 6 0 0
3 3 0 4
Output:
Doolittle factorization failed.
//--------------------------------//
Input:
3
3 -1 3 1
3 6 3 0
3 3 3 4
Output:
Doolittle factorization failed.
//--------------------------------//
Input:
7
1.0 0.0 2.0 0.0 3.0 0.0 4.0 3
3.0 -1.0 0.5 8.0 2.2 1.6 0.0 8
0.0 0.0 0.0 4.5 3.2 2.0 1.0 2
2.0 3.0 5.0 0.0 0.0 0.0 2.0 4
-2.0 -3.0 1.0 1.0 0.0 0.0 3.3 1
2.5 4.5 0.0 0.0 1.0 0.0 0.0 -2
-0.5 -1.5 3.0 2.0 0.0 1.0 -1.0 5
Output:
Doolittle factorization failed.
//--------------------------------//
Input:
3
1.00000000 0.50000000 0.33333333 1.0
0.50000000 0.33333333 0.25000000 1.0
0.33333333 0.25000000 0.20000000 1.0
Output:
Result of direct method:
3.00000408
-24.00002076
30.00001920
//--------------------------------//
Input:
4
1.00000000 0.50000000 0.33333333 0.25000000 1.0
0.50000000 0.33333333 0.25000000 0.20000000 1.0
0.33333333 0.25000000 0.20000000 0.16666667 1.0
0.25000000 0.20000000 0.16666667 0.14285714 1.0
Output:
Result of direct method:
-4.00028881
60.00328814
-180.00799473
140.00523622
//--------------------------------//

欢迎批评指正!

你可能感兴趣的:(数值分析实验,算法实现)