【问题标题】:Java normal distribution with mean diff than zero and std deviance different than oneJava 正态分布,均值不等于 0,标准差不等于 1
【发布时间】:2012-05-02 15:12:55
【问题描述】:

我的教授正在模拟客户到银行。 它表示客户遵循具有 3.5 均值和 1.3 标准偏差的正态分布。

问题是我在理解为什么使用此代码时遇到了一些困难。 我相信他提供的代码是接收流、均值和标准来生成随机数

代码

public class Random {

    private static double second=0;

    static double normal(int stream, double mean, double std){
        double v1=0, v2=0, y1, y2, x1, x2, w=2;

        if (second!=0 ){
            return second;
        }

        while(w>1){
            v1=2*RandomGenerator.rand(stream)-1;
            v2=2*RandomGenerator.rand(stream)-1;
            w=Math.pow(v1,2)+Math.pow(v2,2);
        }

        y1=v1*Math.pow((-2*Math.log(w))/w, 0.5);
        y2=v2*Math.pow((-2*Math.log(w))/w, 0.5);
        x1=mean+y1*std;
        x2=mean+y2*std;
        second=x2;
        return x1;
    }

} 

我的数学课是很多年前的,所以理解这个正态分布有点困难,在网上搜索了如何计算正态分布后,我找不到任何类似于给定代码的公式。

所以,这些是我的问题。

  1. second 有什么作用?这是某种保护?
  2. 这段代码如何使用正态分布?好像没看懂……

【问题讨论】:

  • 请告诉你的教授他应该学会正确地命名他的变量
  • @chburd :) 我也认为 vars 名称应该更具解释性
  • 还请告诉您的教授,到达通常被建模为泊松分布,而不是正态分布。

标签: java normal-distribution


【解决方案1】:

我将按相反的顺序回答问题。该方法的核心部分是一种标准技术,用于将从 [0, 1] 上的均匀分布中抽取的两个随机变量转换为从具有给定均值和标准差的正态分布中抽取的两个随机变量。 (称为Box-Muller transform。)while 循环使用生成和测试技术从单位圆上的二维均匀分布生成随机点 (v1, v2)。从 (v1, v2) 到 (y1, y2) 的映射将均匀分布转换为具有零均值和单位标准偏差的二维正态分布。然后对其进行移位和缩放以获得具有所需均值和标准差的 (x1, x2)。

现在有了生成正态分布变量对的方法,其余代码的工作方式如下:如果second == 0,这是一个需要生成新值的信号,所以它通过@987654325 @ 并生成一对值。然后它将其中一个值保存在second 中并返回另一个。下次调用该方法时,它会注意到 second 中有一个有效值并立即返回,而不是生成更多值。

代码中有一个重大错误:second 应在返回值之前重置为零;否则它总是会继续返回第二个随机值(在第二次调用后看起来不会那么随机)。即使这个缺陷得到了纠正,还有第二个问题。每个其他返回值的值为 0 的概率为零。理论上这并不算太糟糕,因为正态分布的随机样本的值恰好为零的概率是……零!但是,这仍然是一个缺陷。

我将代码重写如下:

public class Random {

    private static double second;
    private static boolean secondValid = false;

    static double normal(int stream, double mean, double std) {
        double v1, v2, y1, y2, x1, x2, w;

        if (secondValid) {
            secondValid = false;
            return second;
        }

        do {
            v1 = 2 * RandomGenerator.rand(stream) - 1;
            v2 = 2 * RandomGenerator.rand(stream) - 1;
            w = v1 * v1 + v2 * v2;
        } while (w > 1);

        y1 = v1 * Math.sqrt(-2 * Math.log(w) / w);
        y2 = v2 * Math.sqrt(-2 * Math.log(w) / w);
        x1 = mean + y1 * std;
        x2 = mean + y2 * std;
        second = x2;
        secondValid = true;
        return x1;
    }

}

【讨论】:

  • 我也会删除所有静态引用,因为这不是线程安全的。
  • @jontro - 删除 static 限定符无助于线程安全。这只是意味着一个人可以拥有多个Random 对象,其私有存储为second。我认为这是有限的效用。对Random 实例的并发访问仍然是不安全的。
  • 是的,当然。但是,如果我使用静态方法,我认为它是线程安全的。如果它是一个可变类,我会知道要么同步调用,要么在有意义的地方创建一个新实例。无论如何,也许这超出了这个问题的范围。
  • @jontro - 我不会假设静态方法是线程安全的,因为它是静态的。碰巧,Math.random() 是线程安全的,但这已明确记录在案:“此方法已正确同步,允许多个线程正确使用。”
  • @TedHopp 感谢您的解释。就事论事。首先,我添加了另一个问题。第二。你说这个然后移动和缩放以获得具有所需平均值和标准偏差的 (x1, x2)。 我在哪里可以学到这个?我明白它的作用,但不明白为什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 2018-07-25
  • 2010-12-16
  • 2017-05-18
相关资源
最近更新 更多