數值概率算法


1、用隨機投點法計算pi

  設有一半徑為r的圓及其外切四邊形。向該正方形隨機地投擲n個點。設落入圓內的點數為k。由於所投入的點在正方形上均勻分布,因而所投入的點落入圓內的概率為(PI * pow(r,2)) / (4 * pow(r,2)) = PI / 4 。所以當n足夠大時,k與n之比就逼近這一概率。從而,PI 約等於 (4*k)/n.如下圖:

實現:

#include <iostream>
#include <cstdlib>
#include <limits>
using namespace std;

// 獲得0-1之間的隨機數
double get_random_num ()
{
    return (double)rand () / RAND_MAX ;
}
// 用隨機投點法計算 PI
double darts (int n)
{
    int k = 0 ;
    for (int i = 0; i < n; ++ i) {
        double x = get_random_num() ;
        double y = get_random_num() ;
        if ((x * x + y * y) <= 1.0) {
            ++ k ;
        }
    }
    return (4 * k) / (double)n ;
}
int main()
{
    cout << darts (200000000) << endl ;
}
View Code

實現結果:

2.計算定積分

設f(x)是[0,1]上的連續函數,且0 <= f(x) <= 1。

需要計算的積分為,積分I等於圖中的面積G。

在圖所示單位正方形內均勻地作投點試驗,則隨機點落在曲線下面的概率為

假設向單位正方形內隨機地投入n個點(xi,yi)。如果有m個點落入

G內,則隨機點落入G內的概率

假定 f(x) = x * x (0 <= x <= 1)計算定積分

實現:

#include <iostream>
#include <cstdlib>
using namespace std;

// 獲得0-1之間的隨機數
double get_random_num ()
{
    return (double)rand () / RAND_MAX ;
}
// 用隨機投點法計算 y = pow(x,2)定積分
double darts (int n)
{
    int k = 0 ;
    for (int i = 0; i < n; ++ i) {
        double x = get_random_num() ;
        double y = get_random_num() ;
        if (y <= x * x) {
            ++ k ;
        }
    }
    return k / (double)n ;
}
int main()
{
    cout << darts (10000000) << endl ;
    return 0;
}
View Code

運行結果:

3.解非線性方程組

求解下面的非線性方程組

 

其中,x1,x2,…,xn是實變量,fi是未知量x1,x2,…,xn的非線性實函數。要求確定上述方程組在指定求根范圍內的一組解

 

問題分析

     解決這類問題有多種數值方法,如:牛頓法、擬牛頓法、粒子群算法等。最常用的有線性化方法和求函數極小值方法。為了求解所給的非線性方程組,構造一目標函數

     式中,x=(x1,x2,……xn)。易知,函數取得零點即是所求非線性方程組的一組解。

 求解思路

    在指定求根區域D內,選定一個隨機點x0作為隨機搜索的出發點。在算法的搜索過程中,假設第j步隨機搜索得到的隨機搜索點為xj。在第j+1步,計算出下一步的隨機搜索增量dxj。從當前點xj依dxj得到第j+1步的隨機搜索點。當x<時,取為所求非線性方程組的近似解。否則進行下一步新的隨機搜索過程。

實現:

//隨機化算法 解線性方程組
#include "stdafx.h"
#include "RandomNumber.h"
#include <iostream>
using namespace std;
 
bool NonLinear(double *x0,double *dx0,double *x,double a0,
                    double epsilon,double k,int n,int Steps,int M);
double f(double *x,int n);
 
int main()
{
    double  *x0,                //根初值
            *x,                    //
            *dx0,                //增量初值
            a0 = 0.0001,            //步長
            epsilon = 0.01,        //精度
            k = 1.1;            //步長變參
    int n = 2,                    //方程個數
        Steps = 10000,            //執行次數
        M = 1000;                //失敗次數
 
    x0 = new double[n+1];
    dx0 = new double[n+1];
    x = new double[n+1];
 
    //根初值
    x0[1] = 0.0;
    x0[2] = 0.0;
 
    //增量初值
    dx0[1] = 0.01;
    dx0[2] = 0.01;
 
    cout<<"原方程組為:"<<endl;
    cout<<"x1-x2=1"<<endl;
    cout<<"x1+x2=3"<<endl;
 
    cout<<"此方程租的根為:"<<endl;
 
    bool flag = NonLinear(x0,dx0,x,a0,epsilon,k,n,Steps,M);
    while(!flag)
    {        
        flag = NonLinear(x0,dx0,x,a0,epsilon,k,n,Steps,M);
    }    
    for(int i=1; i<=n; i++)
    {
        cout<<"x"<<i<<"="<<x[i]<<" ";
    }
    cout<<endl;
 
    return 0;
}
 
//解非線性方程組的隨機化算法
bool NonLinear(double *x0,double *dx0,double *x,double a0,
                    double epsilon,double k,int n,int Steps,int M)
{
    static RandomNumber rnd;
    bool success;            //搜索成功標志
    double *dx,*r;
 
    dx = new double[n+1];    //步進增量向量
    r = new double[n+1];    //搜索方向向量
    int mm = 0;                //當前搜索失敗次數
    int j = 0;                //迭代次數
    double a = a0;            //步長因子
 
    for(int i=1; i<=n; i++)
    {
        x[i] = x0[i];
        dx[i] = dx0[i];
    }
 
    double fx = f(x,n);        //計算目標函數值
    double min = fx;        //當前最優值
 
    while(j<Steps)
    {
        //(1)計算隨機搜索步長
        if(fx<min)//搜索成功
        {
            min = fx;
            a *= k;
            success = true;
        }
        else//搜索失敗
        {
            mm++;
            if(mm>M)
            {
                a /= k;
            }
            success = false;
        }
 
        if(min<epsilon)
        {
            break;
        }
 
        //(2)計算隨機搜索方向和增量
        for(int i=1; i<=n; i++)
        {
            r[i] = 2.0 * rnd.fRandom()-1;
        }
 
        if(success)
        {
            for(int i=1; i<=n; i++)
            {
                dx[i] = a * r[i];
            }
        }
        else
        {
            for(int i=1; i<=n; i++)
            {
                dx[i] = a * r[i] - dx[i];
            }
        }
 
        //(3)計算隨機搜索點
        for(int i=1; i<=n; i++)
        {
            x[i] += dx[i];
        }
 
        //(4)計算目標函數值
        fx = f(x,n);
        j++;
    }    
 
    if(fx<=epsilon)
    {
        return true;
    }
    else
    {
        return false;
    }
}
 
double f(double *x,int n)
{
    return (x[1]-x[2]-1)*(x[1]-x[2]-1)
            +(x[1]+x[2]-3)*(x[1]+x[2]-3);
}
View Code

運行結果:

參考:王曉東《算法設計與分析》第二版

            https://www.cnblogs.com/chinazhangjie/archive/2010/11/11/1874924.html

            https://blog.csdn.net/liufeng_king/article/details/9029091


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM