浅谈随机化算法

一.线性同余法

        随机数在计算机中扮演重要角色,不过现实中往往难以产生真正的随机数,很多教材上都采用了线性同余法,产生的随机数也只是在一定范围内,该范围的一定要比研究所使用的范围大,不能没有完全验证就又循环。

        好事者称上面的性质为随机数要具有周期性,又要不具有周期性(晕),所谓周期性指的是到达一个足够大的数后又要重新开始,非周期性实际就是指范围要足够大,就像C/C++中要求RAND_MAX至少要是32767。

2010111115110229

        其中b >= 0,c >= 0,d <= m。d称为该随机序列的种子。如何选取该方法中的常数b、c和m直接关系到所产生的随机序列的随机性能,不过这是随机性理论研究的内容,不在本文讨论的范围。从直观上看,m应取得充分大,因此可取m为机器大数,另外应取gcd(m, b) = 1,因此可取b为一素数。

        具体原理请读者参考《抽象代数》。

二.随机投点法计算PI值

        其实我最先想到是蒲丰投针实验……请各位读者尽情发挥想象。

        随手谷歌之,发现只要是介绍随机算法的都有这个例子,不过几乎都是C++版本,下面笔者就用Java实现以慰劳广大Java爱好者。

        实验设计如下:

        设有一半径为r的圆及其外切四边形,向该正方形随机地投掷n个点,设落入圆内的点数为m。由于所投入的点在正方形上均匀分布,因而所投入的点落入圆内的概率为圆面积/正方型面积= PI / 4 (与r无关),所以当n足够大时,k与n之比就逼近这一概率,从而,PI 约等于 (4*m)/n。

       Java实现:

/*
 * 遇到了很奇怪的问题,名字叫CalPI就一直找不到主类
 * bin目录下确实没有class文件
 * 咋回事
 */
public class MyPI {

    public static void main(String[] args) {
        int n = 20000000;//进行200w次实验
        int count = calCounts(n);
        double ans = 4.0*count/n;
        System.out.println(ans);
    }

    private static int calCounts(int n) {
        /*
         * java中没有类似C/C++中的fabs,不过abs重载了
         * 如何让Math.random()生成的随机数包括1?
         */
        int count = 0;
        for(int i=0; i<n; i++) {
            double x = Math.random();
            double y = Math.random();
            //实际有些问题,因为无法生成1.0,目前我也不知道咋办
            if((x*x + y*y)<=1.0) {
                count++;
            }
        }
        return count;
    }

}

        结果如下:

200 3.1418832
2000 3.088
20000 3.1512
200000 3.14414
2000000 3.140148
20000000 3.1415662

        观察结果可得并不是试验次数越多结果越精确,而且相同的次数结果也会不同。

三.简单定积分计算

        采用概率方法,不以积分公式。

        假定f(x)为[0,1]上的连续可积函数(其实什么叫可积我也忘了),现需要计算1,实际就等于G浅谈随机化算法_第1张图片

        分析如下:在图所示单位正方形内均匀地作投点试验n次,则随机点落在曲线下面的概率为3,如果有m个点落在G内,则概率P=m/n,由古典概型可知I=P。

        如果f(x) = ex(x用上标,后面的也在上标里,选中后面的再次单击上标按钮,或者直接在源代码里改<sup>的范围),则只需要把上面的calCounts里的if改成y<x^3并且输出不乘以4就好了。

四. 舍伍德(Sherwood)算法 

五.拉斯维加斯(Las Vegas)算法

六.蒙特卡罗(Monte Carlo)算法      

注意:四五六准备出独立文章    


你可能感兴趣的:(浅谈随机化算法)