概率算法
概率算法的特性:使用概率算法去处理同一个问题,计算两次会得到不同的计算结果。概率算法是对于我们在现实社会中是非常有效的,大家都是学理工科的,知道这里世界上是没有绝对的事情,也没有绝对发生的事情。我们认为一些事情会发生了,它也不是绝对发生,也可以认为它发生是存在着一定的可能性,只是认为可能性发生的大小而决定的。我认为我们要把计算机当成自己的tool to sovle social problems。How to use it 是一个关键,也就是将我们的现实中的问题给抽象出来。我们该如何去建立这种模型,该模型该如何去理清关系。模型实际上可以抽象在一个大坐标系中建立它的位置,我们可以来预测将来发生着什么。
我们把模型发生或是要发生的事情抽象成一个事件,该事件是如何来预测发生了还是没有发生?这就是取决其相对发生的概率问题。例如:现实生活中,我们的小孩子最爱玩的是剪刀石头布游戏,我们有m个孩子一起玩这个,有着3中不同出拳的方式,m个孩子中想要一个孩子给胜出。小明恰好是其中的一个聪明的孩子,他在一旁开始统计着每个孩子可能出现的出拳的方式,如果你能给猜到,你实际上有很大的概率胜出。可是经过足够多的统计发现:每个孩子出剪刀、石头、布的方式都是集中在:0.33左右,也就是每个出现的概率是基本相等的。这存在着一种随机性在其中。如果我们把他们都给抽象成一个entity,统计分别出现的次数和出拳的可能性,在足够多的次数情况下其实可以分析出一个实体可能出现的方式。(这是基于statistics)
回到我们的计算机世界,我们要用计算机这个工具来帮我们来解决一个实际问题:我们想要计算一座大桥的车流量问题。一座长M公里的大桥,我们要分析该桥的车流量。而我们比如人只有2人,如果我们有足够多的人,我们就是通过计数都可以知道,这显然是不科学的。我们两个人放一个桥头计数,放一个桥尾计数,取一个平均数,好像是不准确的。我们测量出来的数据也是不准确的。我们好像还学过微积分哈,我们可以使用问积分的方法来解决它哈。这个车流量本来就不是一个准确值,我们要的是一个近似值,减小误差。我们很简单的测量一个小的距离内的车流量,这样我们就有了基础,也就是可以看成M公里的大桥上的一段,我们 现在简单从0~M进行积分,求解出来该值也就是车流量的值。
关键的核心是去解决怎样解决定积分问题?
方法一、概率方法(有数据足够大)
C++写的一个随机函数类,要注意一个问题有符号数就是在计算机的右移问题 "<<"可能是逻辑右移,也可能是算术右移,这取决于计算的操作系统(C/C++),如果是java “<<<”逻辑右移哈,这里就不考虑该问题。
class Random{
private:
long seed;
long mutilply=0x5deece66l;
long adder=0xbl;
long mask=(1L<<48)-1;
public:
Random()
{
seed=time(NULL);
}
Random(const long &seed)
{
if(seed!=0)
this->seed=seed;
else
this->seed=time(NULL);
}
int random(const int &n)
{
if(n<=0)
err_quit("error");
seed=(seed*mutilply+adder)&mask;
return ((int)(seed>>17)%n);
}
double frandom()
{
return this->random(Max)/(double)Max;
}
};
//计算的公式为: value=(b-a)/n*求和1~n-1的x的函数值f(Xi)
double darts(const double&a,const double &b, const int &n)
{
Random *ran=new Random();
double y=0;
for(int i=1;i<=n;++i)
{
double x=(b-a)*ran->frandom()+a;
y+=f(x);
}
delete ran;
return (b-a)*y/(double)n;
}
该方法是有随机性的,不是很准确
方法2:复合梯形方法
算法如下:double get_value(double f(double x),double a,double b,int n)
{
double h=(b-a)/(double)n;
double value=0;
for(int i=1;i<=n-1;++i)
{
double x=a+i*h;
value+=2*f(x);
}
return h/2*(f(a)+value+f(b));
}
测试一个f(x)=x*x;
测试用例为:
printf("the value is %.08f\n",get_value(f, 0, 1, 10000));
输出为:
方法3:
smpron方法:
double get_T(double a,double b,int n)
{
double h=(b-a)/(double)n;
double T=(f(a)-f(b))/2;
for(int i=1;i<n;i++)
{
double x=a+h*i;
T+=f(x);
}
return T*h;
}
double get_value(double a,double b,int n)
{
return (get_T(a,b,2*n)*4-get_T(a,b,n))/3;
}
printf("the result of :%.10lf\n",get_value(2,5,10000));
这里简单说明其n越大表示其精度回越高。高斯方法才是精度非常高的方法之一。大学大家都学过高斯函数和高斯公式吧。
我们既然解决了积分问题,但是这里有很大的bug这里解决的简单的连续的函数的问题,有断点出现时候也就是我们思考不全面,还有些函数还不能在目前直接获取其定积分的值。还得继续学习。