Numerical Calculation 数值计算

Numerical Calculation 数值计算

数值计算第一次实验(C语言版)

C语言编程常用数值计算的高性能实现

/* 高位全0,低N位全1 */
#define Low_N_Bits_One(N)     ((1<<N) -1)

/* 高位全1,低N位全0 */
#define Low_N_Bits_Zero(N)    (~((1<<N) -1))

/* 低位第N位置1 */
#define Set_Bit_N(NUM, N)     (NUM | (1 << (N - 1)))

/* 低位第N位置0 */
#define Clear_Bit_N(NUM, N)   (NUM & (~(1 << (N - 1))))

/* 低位第N位反转 */
#define Reverse_Bit_N(NUM, N) ((NUM) ^ (1 << (N - 1)))

/* 上取整 */
#define UpRoun8(Num)  (((Num) + 0x7)  & (~0x7))
#define UpRoun16(Num) (((Num) + 0xf)  & (~0xf))
#define UpRoun32(Num) (((Num) + 0x1f) & (~0x1f))

/* 下取整 */
#define LowRoun8(Num)  ((Num) & (~0x7))
#define LowRoun16(Num) ((Num) & (~0xf))
#define LowRoun32(Num) ((Num) & (~0x1f))

/* 求商 */
#define Div8(Num)         ((Num)>>3)
#define Div16(Num)        ((Num)>>4)
#define Div32(Num)        ((Num)>>5)

/* 余数进位求商 */
#define UpDiv8(Num)        (((Num)>>3) + !!((Num) & 0x7))
#define UpDiv16(Num)        (((Num)>>4) + !!((Num) & 0xf))
#define UpDiv32(Num)        (((Num)>>5) + !!((Num) & 0x1f))

/* 求余 */
#define M8(Num)        ((Num) & 0x7)
#define M16(Num)       ((Num) & 0xf)
#define M32(Num)       ((Num) & 0x1f)

/* 求反余
即求最小的x,满足(Num + x) % 模数 == 0
例如 RM16(Num) 等价于 (16 - Num%16) % 16 */
#define RM8(Num)        ((~(Num) + 1) & 0x7)
#define RM16(Num)        ((~(Num) + 1) & 0xf)
#define RM32(Num)        ((~(Num) + 1) & 0x1f)

线性方程组求解

1. 二分法方程求根 
2. 顺序消元法解线性方程组 
3. 列选主元消去法解线性方程组
4. 全选主元消去法解线性方程组
5. Doolittle(杜立特尔)分解     
6. Crout(克洛特)分解解线性方程组 
7. 平方根法法解线性方程组       
8. 拉格朗日插值法                 
9.  牛顿插值法       
10. Hermite插值法                
11. 最小二乘法(线性拟合)     
12. 变步长梯形求积法计算定积分  
13.  Romberg算法    
14.  改进欧拉法  

main.c

#include 
#include 
#include 
#include "head.h"

// 这些函数 的实现在 head.h头文件中
double f(double);   //方 程f(x)=0的函数
double f2(double);  //变步长积分函数
void Dodichotomy();   //二分法
void Doleastsquares();    //最小二乘法
void Doshunxu();    //顺序消元法
void Doliezhu();    //列主消元法
void Doquanxuan();  //全选主元消去
void Dodoolittle(); //杜利特尔分解法
void Docrout(); //Crout(克洛特)分解解线性方程组
void Dopingfang();  //平方根法解线性方程组
void Dolagrange();  //拉格朗日插值法
void Donewton();    //牛顿插值法
void Dohermite();   //Hermite插值法
void Doleastsquares();  //最小二乘法
void Dochangestep();    //变步长梯形求积法计算定积分
void Doromberg();   //龙贝格算法
void Doeuler(); //改进欧拉算法

int main()
{
    char ch;
    int n;
    for(;;)
    {
        n = Menu();
        switch(n)
        {
            case 1:
                Dodichotomy();
                break;
            case 2:
                Doshunxu();
                break;
            case 3:
                Doliezhu();
                break;
            case 4:
                Doquanxuan();
                break;
            case 5:
                Dodoolittle();
                break;
            case 6:
                Docrout();
                break;
            case 7:
                Dopingfang();
                break;
            case 8:
                Dolagrange();
                break;
            case 9:
                Donewton();
                break;
            case 10:
                Dohermite();
                break;
            case 11:
                Doleastsquares();
                break;
            case 12:
                Dochangestep();
                break;
            case 13:
                Doromberg();
                break;
            case 14:
                Doeuler();
                break;
            case 15:
                return 0;
            default:
                printf("输入错误,请重新输入\n");
                break;
        }
    }
}

void Dodichotomy()
{
    printf("%lf\n",Dichotomy(f,-4,4,1e-5));
}

void Doleastsquares()
{
    double x[5] = {1,2,3,4,5};
    double y[5] = {0,2,2,5,4};
    double a,b;
    LeastSquares(x,y,5,&a,&b);
    printf("a = %lf;b = %lf\n",a,b);
}

double f(double x)
{
    double y;
    y = x*(x*(2.0*x-4.0)+3.0)-6.0;
    return y;
}

void Doshunxu()
{
    double a[3][3]={
                   2.5,2.3,-5.1,
                   5.3,9.6,1.5,
                   8.1,1.7,-4.3
                   };
    double b[3] = {3.7,3.8,5.5};

    Shunxu(a,3,3,b);
}

void Doliezhu()
{
    double a[3][3]={
                   2.5,2.3,-5.1,
                   5.3,9.6,1.5,
                   8.1,1.7,-4.3
                   };
    double b[3] = {3.7,3.8,5.5};

    Liezhu(a,3,3,b);
}

void Doquanxuan()
{
    double a[3][3]={
                   2.5,2.3,-5.1,
                   5.3,9.6,1.5,
                   8.1,1.7,-4.3
                   };
    double b[3] = {3.7,3.8,5.5};

    Quanxuan(a,3,3,b);
}

void Dodoolittle()
{
    float a[3][3] = {
                    1,-1,3,
                    2,-4,6,
                    4,-9,2
    };
    float b[4] = {1,4,1};
    Doolittle(a,3,3,b);
}

void Docrout()
{
    float a[3][3] = {
                    1,-1,3,
                    2,-4,6,
                    4,-9,2
    };
    float b[4] = {1,4,1};
    Crout(a,3,3,b);
}

void Dopingfang()
{
    int i;
    double a[4][4] = {
                     {1,2,1,-3},
                     {2,5,0,-5},
                     {1,0,14,1},
                     {-3,-5,1,15}
        };
    double b[4] = {1,2,16,8};
    double d[4] = {0};
    double x[4] = {0};
    double y[4] = {0};
    double L[4][4] = {0};
    Cholesky(a,b,L,d,x,y,4);
    printf("方程的解为:\n");
    for(i=1;i<=4;i++)
        printf("x(%d)=%f\n",i,x[i-1]);
}

void Dolagrange()
{
    Point points[20] = {{0.56160,0.82741},{0.56280,0.82659},
                        {0.56401,0.82577},{0.56521,0.82495}
    };
    Lagrange(points,4,0.5635);
}

void Donewton()
{
    double b[6][7] = {
        {0.4,0.41075},
        {0.55,0.57815},
        {0.65,0.69675},
        {0.80,0.88811},
        {0.90,1.02652},
        {1.05,1.25382}
    };
    Newton(b,6,0.596);
}

void Dohermite()
{
    static double xi[3] = {0.1,0.3,0.5};
    static double yi[3] = {0.099833,0.295520,0.479426};
    static double dyi[3] = {0.995004,0.955336,0.877583};
    Hermite(0.4,xi,yi,dyi,3,1.0e-12);
}

double f2(double x)
{
    double sum;
    if(x = 0) return 1;
    sum = sin(x)/x;
    return sum;
}

void Dochangestep()
{
    Changestep(f2,1,2,0.0000001);
}

double f3(double x,double y)
{
    return -y + x + 1;
}

void Doromberg()
{
    Romberg(f2,0,1,0.0000001);
}

void Doeuler()
{
    Euler(f3,0,0.5,1,5);
}

head.h

/*
* 输入点结构
*/
typedef struct stPoint
{
    double x;
    double y;
}Point;

/*
* 开始菜单
*/
int Menu()
{
    int n;
    printf("----------------数值实验------------------\n");
    printf("|                                        |\n");
    printf("|     [1]:二分法方程求根                 |\n");
    printf("|     [2]:顺序消元法解线性方程组         |\n");
    printf("|     [3]:列选主元消去法解线性方程组     |\n");
    printf("|     [4]:全选主元消去法解线性方程组     |\n");
    printf("|     [5]:Doolittle(杜立特尔)分解        |\n");
    printf("|     [6]:Crout(克洛特)分解解线性方程组  |\n");
    printf("|     [7]:平方根法法解线性方程组         |\n");
    printf("|     [8]:拉格朗日插值法                 |\n");
    printf("|     [9]:牛顿插值法                     |\n");
    printf("|     [10]:Hermite插值法                 |\n");
    printf("|     [11]:最小二乘法(线性拟合)          |\n");
    printf("|     [12]:变步长梯形求积法计算定积分    |\n");
    printf("|     [13]:Romberg算法                   |\n");
    printf("|     [14]:改进欧拉法                    |\n");
    printf("|     [15]:退出                          |\n");
    printf("|                                        |\n");
    printf("------------------------------------------\n");
    printf("请输入你要选择的操作:");
    scanf("%d",&n);
    return n;
}

/*
* 二分法方程求根
* fun: 求方程fun(x) = 0的函数fun(x)
* left: 根区间左边点
* right: 根区间右边点
* eps:  二分法的精度
*/
double Dichotomy(double (*fun)(double),double left,double right,double eps)
{
    double yleft,yright,ym;
    double middle;
    do
    {
        yleft = fun(left);
        yright = fun(right);
        middle = (left + right)/2;
        ym = fun(middle);
        if(ym*yleft < 0)
        {
            right = middle;
        }
        else
        {
            left = middle;
        }
    }while(fabs(ym) >= eps);
    return left;
}

/*
* 高斯顺序消元法
* a[][]:系数矩阵
* n,m:系数矩阵的维数
* b[]:常数矩阵
*/
void Shunxu(double (*a)[3],int n,int m,double b[])
{
    int i,j,t,tmp;
    double x[20];
    //下面高斯顺序消元
    for(i = 0 ; i < n ; i++)//将矩阵化成上三角矩阵
        for(j = i+1 ; j < m ; j++)
        {
            tmp = a[j][i]/a[i][i];
            for(t = i+1 ; t < m; t++)
                a[j][t] = a[j][t] - tmp*a[i][t];
            b[j] = b[j] - tmp*b[i];
            a[j][i] = 0;
        }
    //回代
    x[n-1] = b[n-1]/a[n-1][n-1];
    for(i = n-2 ; i >= 0 ; i--)
    {
        x[i] = b[i];
        for(j = i+1 ; j < m ; j++)
            x[i] -= a[i][j]*x[j];
            x[i]/=a[i][i];
    }

    //输出结果
    printf("结果为:\n");
    for(i = 0 ; i < n ; i++)
        printf("x[%d] = %lf\n",i+1,x[i]);
}

/*
* 获取主元所在的行
* a[][]: 系数矩阵
* n: 系数矩阵的维数
* k: 所在的列
*/
int getMaxzhu(double (*a)[3],int n,int k)
{
    int i;
    int laber = k;
    double maxlaber = 0;

    for(i = k ; i < n ; i++)
    if(maxlaber < fabs(a[i][k]))
    {
        maxlaber = fabs(a[i][k]);
        laber = i;
    }
    return laber;
}

/*
* 高斯列主消元法
* a[][]:系数矩阵
* n,m:系数矩阵的维数
* b[]:常数矩阵
*/
void Liezhu(double (*a)[3],int n,int m,double b[])
{
    int i,j,t,tmp,laber;
    double x[20];
    //高斯消元法
    for(i = 0 ; i < n ; i++)
    {
        laber = getMaxzhu(a,3,i);
        if(laber != i)
        {
            for(j = 0 ; j < m ; j++)
            {
                tmp = a[i][j];
                a[i][j] = a[laber][j];
                a[laber][j] = tmp;
            }
            tmp = b[laber];
            b[laber] = b[i];
            b[i] = tmp;
        }
        //消元
       for(j = i+1 ; j < m ; j++)
       {
            tmp = a[j][i]/a[i][i];
            for(t = i+1 ; t < m; t++)
                a[j][t] = a[j][t] - tmp*a[i][t];
            b[j] = b[j] - tmp*b[i];
            a[j][i] = 0;
       }
    }
    //回代
    x[n-1] = b[n-1]/a[n-1][n-1];
    for(i = n-2 ; i >= 0 ; i--)
    {
        x[i] = b[i];
        for(j = i+1 ; j < m ; j++)
            x[i] -= a[i][j]*x[j];
            x[i]/=a[i][i];
    }

    //输出结果
    printf("结果为:\n");
    for(i = 0 ; i < n ; i++)
        printf("x[%d] = %lf\n",i+1,x[i]);
}

/*
* 根据L和U的矩阵求解方程组的解
* l[][20]: 矩阵L u[][20]: 矩阵U
* b[]: 常数矩阵
* x[]: 解的矩阵
* n: 维数
*/
void solve(float l[][20],float u[][20],float b[],float x[],int n)
{
    int i,j;
    float t,s1,s2;
    float y[20];

    //第一次回带过程
    for(i = 0 ; i < n ; i++)
    {
        s1 = 0 ; 
        for(j = 0 ; j < i-1 ; j++)
        {
            t = -l[i][j];
            s1 = s1 + t*y[j];
        }
        y[i] = (b[i] + s1)/l[i][i];
    }

    for(i = n-1 ; i >= 0 ; i--)
    {
        s2 = 0;
        for(j = n-1 ; j > i-1 ; j--)
        {
            t = -u[i][j];
            s2 = s2 + t*x[j];
        }
        x[i] = (y[i] + s2)/u[i][i];
    }
}

/*
* 高斯全选主元消元法
* a[][]:系数矩阵
* n,m:系数矩阵的维数
* b[]:常数矩阵
*/
void Quanxuan(double (*a)[3],int n,int m,double b[])
{
    int i,j,t,p,tmp,max,w = 0,y = 0;
    double x[20];
    for(i = 0 ; i < n ; i++)
    {
        for(p = i ; p < m ; p++)
        {
            max = getMaxzhu(a,3,p);
            if(a[w][y] < a[max][p])
            {
                w = max;
                y = p;
            }
        }
        for(j = 0 ; j < m ; j++)
        {
            tmp = a[i][j];
            a[i][j] = a[w][j];
            a[w][j] = tmp;
        }
        for(j = i ; j < n;  j++)
        {
            tmp = a[j][i];
            a[j][i] = a[i][y];
            a[i][y] = tmp;
        }
        //消元
       for(j = i+1 ; j < m ; j++)
       {
            tmp = a[j][i]/a[i][i];
            for(t = i+1 ; t < m; t++)
                a[j][t] = a[j][t] - tmp*a[i][t];
            b[j] = b[j] - tmp*b[i];
            a[j][i] = 0;
       }
    }
    //回代
    x[n-1] = b[n-1]/a[n-1][n-1];
    for(i = n-2 ; i >= 0 ; i--)
    {
        x[i] = b[i];
        for(j = i+1 ; j < m ; j++)
            x[i] -= a[i][j]*x[j];
            x[i]/=a[i][i];
    }

    //输出结果
    printf("结果为:\n");
    for(i = 0 ; i < n ; i++)
        printf("x[%d] = %lf\n",i+1,x[i]);
}

/*
* Doolittle(杜利特尔分解法)
* (*a)[4]: 系数矩阵a
* int m,n: 矩阵a的维数
* b[]: 矩阵b
*/
void Doolittle(float (*a)[3],int n,int m,float b[])
{
    float l[20][20],u[20][20],x[20];
    int i,j,k;
    float s1,s2;
    // 将所有的数组置零,同时将L矩阵的对角值设为1 
    for(i = 0 ; i < 20 ; i++)
        for(j = 0 ; j < 20 ; j++ )
        {
            l[i][j] = 0;
            u[i][j] = 0;
            if(j == i) l[i][j] = 1;
        }

    // 下面求解矩阵L和U
    for(i = 0 ; i < n ; i++)
    {
        for(j = i ; j <= n ; j++)
        {
            s1 = 0;
            for(k = 0 ; k < i-1 ; k++)
                s1 = s1 + l[i][k]*u[k][j];
            u[i][j] = a[i][j] - s1;
        }
        for(j = i+1; j < n ;j++)
        {
            s2 = 0; 
            for(k = 0 ; k < i-1 ; k++)
                s2 = s2 + l[j][k]*u[k][i];
            l[j][i] = (a[j][i] - s2)/u[i][i];
        }
    }
    printf("array L:\n");/*输出矩阵L*/
    for(i = 0;i < n;i++)
    {
        for(j = 0;j < n;j++)
            printf("%7.3f ",l[i][j]);
        printf("\n");
    }
    printf("array U:\n");/*输出矩阵U*/
    for(i = 0;i < n;i++)
    {
        for(j = 0;j < n;j++)
            printf("%7.3f ",u[i][j]); printf("\n");
    }
    solve(l,u,b,x,n);
    printf("解为:\n");
    for(i = 0 ; i < n ; i++)
    {
        printf("x%d = %f\n",i,x[i]);
    }
}

/*
* (*a)[3]: 系数矩阵a
* int n,m: 矩阵a的维数
* b[]: 常数矩阵
*/
void Crout(float (*a)[3],int n,int m,float b[])
{
    int i,j,k;
    float l[20][20],u[20][20];
    float x[20],y[20];
    // 将所有的数组置零,同时将U矩阵的对角值设为1 
    for(i = 0 ; i < 20 ; i++)
        for(j = 0 ; j < 20 ; j++ )
        {
            l[i][j] = 0;
            u[i][j] = 0;
            if(j == i) u[i][j] = 1;
        }

    l[0][0]=a[0][0];
    for(i = 0 ; i < n ; i++)
    {
        l[i][0]=a[i][0];//计算第一行的l[][]
        u[0][i]=a[0][i]/l[0][0];//计算第一列的u[][]
    }
    for(i = 0 ; i < n - 1 ; i++)
    {
        for(j = 0 ; j <= i ; j++)//计算第2行到第size-1行的l[][]
        {
            l[i][j] = a[i][j];
            for(k = 0 ; k < j ; k++)
            {
                l[i][j] = l[i][j] - l[i][k]*u[k][j];
            }
        }
        printf("\n");
        for(j = i ; j < n ; j++)//计算第2行到第size行的u[][]
        {
            u[i][j] = a[i][j];
            for(k = 0 ; k <= i-1 ; k++)
            {
                u[i][j] = u[i][j] - l[i][k]*u[k][j];
            }
            u[i][j] = u[i][j]/l[i][i];
        }
        printf("\n");
    }
    for(j = 0;j < n;j++)//计算第n行的l[][]
    {
        l[n-1][j]=a[n-1][j];
        for(k=0;k<=j-1;k++)
        {
            l[n-1][j]=l[n-1][j]-l[n-1][k]*u[k][j];
        }
    }

    printf("\n");
    printf("array L:\n");/*输出矩阵L*/
    for(i = 0;i < n;i++)
    {
        for(j = 0;j < n;j++)
            printf("%7.3f ",l[i][j]);
        printf("\n");
    }
    printf("array U:\n");/*输出矩阵U*/
    for(i = 0;i < n;i++)
    {
        for(j = 0;j < n;j++)
            printf("%7.3f ",u[i][j]); printf("\n");
    }
    solve(l,u,b,x,n);
    printf("解为:\n");
    for(i = 0 ; i < n ; i++)
    {
        printf("x%d = %f\n",i,x[i]);
    }
}

/*
* 平方根法法解线性方程组
* a[][],b[]: 系数矩阵
* n: 矩阵的维数
* Cholesky():算法函数
*/
void Cholesky(double a[][4],double b[],double L[][4],double d[],double x[],double y[],int n)
{
    int i,j,k;
    double s;
    for(i=0;i<n;i++)
    L[i][i]=1;
    d[0]=a[0][0];
    for(i=1;i<n;i++)
    {
        for(j=0;j<i;j++)
        {
            s=0;
            for(k=0;k<j;k++)
                s=s+L[i][k]*d[k]*L[j][k];
            L[i][j]=(a[i][j]-s)/d[j];
        }
        s=0;
        for(k=0;k<i;k++)
            s=s+L[i][k]*L[i][k]*d[k];
        d[i]=a[i][i]-s;
    }
    y[0]=b[0];
    for(i=1;i<n;i++)
    {
        s=0;
        for(k=0;k<i;k++)
            s=s+L[i][k]*y[k];
        y[i]=b[i]-s;
    }
    x[n-1]=y[n-1]/d[n-1];
    for(i=n-2;i>=0;i--)
    {
        s=0;
        for(k=i+1;k<n;k++)
        s=s+L[k][i]*x[k];
        x[i]=y[i]/d[i]-s;
    }
    for(i=1;i<=n;i++)
        printf("d(%d)=%f\n",i,d[i-1]);
    printf("矩阵L为:\n");
    for(i=0;i<n;i++)
    {
        for(j=0;j<=i;j++)
            printf("%f    ",L[i][j]);
        printf("\n");
    }
}

/*
* Point *point: 插值节点结构体指针
* int n: 插值点的个数
* double s: 待求插值点
*/
void Lagrange(Point *points,int n,double x)
{
    int i,j;
    double tmp,lagrange = 0;
    /* tmp:拉格朗日基函数,lagrange:根据拉格朗日函数得出的f(x) */
    //利用拉格朗日插值公式计算函数x的值
    for(i = 0 ; i <= n ; i++)
    {
        for(j = 0 , tmp = 1 ; j <= n ; j++)
        {
            if(j == i)  // 去掉xi与xj相等的情况
                continue;   //范德蒙行列式下标就是j!=k,相等分母就没有意义了
            tmp = tmp*(x - points[j].x)/(points[i].x-points[j].x); //拉格朗日基函数
            lagrange=lagrange+tmp*points[i].y; //最后计算基函数*y,全部加起来,就是该x项的拉格朗日函数了
        }
    }
    //拉格朗日函数计算完毕,代入所求函数x的值,求解就ok了
    printf("\n拉格朗日函数f(%lf)=%lf\n",x,lagrange);
}

/*
* 最小二乘法
* x[],y[]: 观测点数据
* n: 观测点数量
* a,b: y = ax + b,线性拟合的两个系数
*/
void LeastSquares(double x[],double y[],int n,double *a,double *b)
{
    int i;
    double sumx = 0,sumy = 0,sumxx = 0,sumxy = 0;
    for(i = 0 ; i < n ; i++)
    {
        sumx += x[i];
        sumy += y[i];
        sumxx += x[i]*x[i];
        sumxy += x[i]*y[i];
    }

    // n*a + sumx*b = sumy;
    // sumx*a + sumxx*b = sumxy;

    *b = (sumy*sumx - sumxy*n)/(sumx*sumx - sumxx*n);
    *a = (sumy - sumx*(*b))/n;
}

/*
* 牛顿插值法
* b[][]: 均差表
* n: 插值点的个数
* x: 待求插值点
*/
void Newton(double (*b)[7],int n,double x)
{
    double sum = 0,w = 1,cc[2][4];
    // sum:保存牛顿插值多项式
    int i,j,k,m,z = 0;
    // 求均差表
    for(i = 2 , k = 1; i < 7;i++,k++)
    {
        for(j = i - 1 ; j < n ; j++)
        {
            b[j][i] = (b[j-1][j-1] - b[j][i - 1])/(b[j - k][0] - b[j][0]);
        }
    }
    for(m = 0 ; m < 4 ; m++,z = 0)
    {
        cc[0][m] = b[m+1][m+2];
        do{
            w *= (x - b[z][0]);
        }while(z++ != m);
        cc[1][m] = w;
    }
    sum = b[0][1];
    for(m = 0 ; m < 4 ; m++)
        sum += (cc[0][m]*cc[1][m]);
    printf("\n插值y为:%lf\n",sum);
}

void Hermite(double x,double xi[],double yi[],double dyi[],int N,double EPS)
{
    int i,j;
    double li,sum,y,gix[N],hix[N];
    for(i = 0 ; i < N ; i++)
    {
        li = 1.0; sum = 0.0;
        for(j = 0 ; j < N ; j++)
        {
            if(j != i)
            {
                li *= (x - xi[j])/(xi[i] - xi[j]);
                sum += 1.0/(xi[i] - xi[j]);
            }
            li = li*li;
            gix[i] = (1.0 - 2.0*(x - xi[i])*sum)*li;
            hix[i] = (x - xi[i])*li;
        }
        y = 0.0;
        for(i = 0; i < N; i++)
            y += yi[i] * gix[i] + dyi[i] * hix[i];

        printf("x = %15.6e    p(x) = %15.8e\n",x,y);
    }
}

/*
* 变步长梯形求积法计算定积分
* 原理: 利用若干个小梯形面积代替原方程的积分
* fun(): 积分函数
* a,b: 积分上下限
* eps: 误差
*/
void Changestep(double (*fun)(double),double a,double b,double eps)
{
    int i,n; // i为分段变步长的数量
    double fa,fb,h,t1,p,s,x,t;
    // fa,fb: 代表边界值带入函数后的值
    // h: 分段后每个子区间的长度
    // x: 分段后的分段点
    // p: 为当前误差
    fa = fun(a);
    fb = fun(b);
    n = 1;
    h = b - a;
    t1 = h*(fa + fb)/2;
    p = eps + 1;
    while(p >= eps)
    {
        s = 0;
        for(i = 0 ; i <= n-1 ; i++)
        {
            x = a + (i + 0.5)*h;
            s += fun(x);
        }
        t = t1/2 + h*s/2; //根据公式计算
        p = fabs(t1 - t);
        printf("步长为%d时的Tn = %lf\tT2n = %lf\t,误差变化为:%lf\n",n,t1,t,p);
        t1 = t;
        n = n*2;
        h = h/2;
    }
    printf("经过变长梯形求积法得到的方程的结果为:%lf\n",t);
}

/*
* Romberg算法
* fun(): 积分函数
* a,b: 积分上下限
* eps: 误差限
*/
void Romberg(double (*f)(double),double a,double b,double eps)
{
    double h,T1,T2,S,S1,S2,C1,C2,R1,R2,z[100][4];
    //h:分段后每个子区间的长度
    int i,j,k = 1;
    h = b-a;
    T1 = (f(a) + f(b))*h/2;
    z[0][0] = T1;
    while(1)
    {
        S = 0;
        double x;
        for(x = a + h/2; x < b ; x = x+h)
            S += f(x);
        T2 = (T1 + h*S)/2;
        z[k][0] = T2;

        S2 = T2 + (T2 - T1)/3; // 利用T1,T2计算S2
        z[k][1] = S2;

        if(k == 1);
        else{
            C2 = S2 + (S2 - S1)/15; // 利用S1,S2计算C2
            z[k][2] = C2;

            if(k == 2);
            else{
                R2 = C2 + (C2 - C1)/63; //利用C1,C2计算R2
                z[k][3] = R2;

                if(k == 3);
                else{
                    if(fabs(R2 - R1) < eps);
                        break;
                }
                R1 = R2;
            }
            C1 = C2;
        }
        k++;
        h /= 2;
        T1 = T2;
        S1 = S2;
    }
    printf("%3c%6c%12c%12c%12c\n",'k','T','S','C','R');
    for(i = 0; i < k;i++)
    {
        printf("%3d",i);
        if(i < 3)
        {
            for(j = 0 ; j <= i ; j++)
            {
                printf("%12.7lf",z[i][j]);
            }
            printf("\n");
        }
        else
        {
            for(j = 0;j < 4 ; j++)
            {
                printf("%12.7lf",z[i][j]);
            }
            printf("\n");
        }
    }
}

/*
* 改进的欧拉算法
* f(): 积分函数
* a,b: 积分上下限
* y0: 初值
* n: 将区间等分的数目
*/
void Euler(double (*f)(double, double),double a,double b,double y0,int n)
{
    double h;
    double x,y,xn,yn,yp;
    int i;
    h = (b - a)/n;
    x = a;
    y = y0;
    for(i = 1 ; i <= n ; i++)
    {
        xn = x + h;
        yn = y + h*f(x,y);
        yp = yn + h/2*(f(x,y) + f(xn,yn));
        printf("x%d = %lf,y%d = %lf\n",i,xn,i,yp);
        x = xn;
        y = yp;
    }

}

编译
gcc.sh

#!/bin/bash

# File Name : gccfile.sh
# Author : xiaorui
# Created Time :2017年05月01日 星期一 16时47分31秒
# Program Funtion :gcc File

gcc main.c -lm -o main
# -lm: 链接相应的数学库函数

你可能感兴趣的:(c++)