2009-08-20 6 views
10

정수 범위의 시작과 끝이 주어지면이 범위 사이의 정규 분포 난수를 어떻게 계산합니까?정수 범위에서 정규 분포 랜덤을 생성하는 방법은 무엇입니까?

나는 정규 분포가 + + 무한대로 간다는 것을 알고있다. 꼬리가 잘릴 수 있으므로 임의가 임의 범위 밖에서 계산되면 다시 계산할 수 있습니다. 이것은 범위의 정수 확률을 높이지만,이 효과가 허용되는 한 (< 5 %) 괜찮습니다.

public class Gaussian 
{ 
    private static bool uselast = true; 
    private static double next_gaussian = 0.0; 
    private static Random random = new Random(); 

    public static double BoxMuller() 
    { 
     if (uselast) 
     { 
      uselast = false; 
      return next_gaussian; 
     } 
     else 
     { 
      double v1, v2, s; 
      do 
      { 
       v1 = 2.0 * random.NextDouble() - 1.0; 
       v2 = 2.0 * random.NextDouble() - 1.0; 
       s = v1 * v1 + v2 * v2; 
      } while (s >= 1.0 || s == 0); 

      s = System.Math.Sqrt((-2.0 * System.Math.Log(s))/s); 

      next_gaussian = v2 * s; 
      uselast = true; 
      return v1 * s; 
     } 
    } 

    public static double BoxMuller(double mean, double standard_deviation) 
    { 
     return mean + BoxMuller() * standard_deviation; 
    } 

    public static int Next(int min, int max) 
    { 
     return (int)BoxMuller(min + (max - min)/2.0, 1.0); 
    } 
} 

아마도 표준 편차의 범위를 범위에 비례 할 필요가 있지만이를 이해할 수는 없습니다.

답변 :

// Will approximitely give a random gaussian integer between min and max so that min and max are at 
    // 3.5 deviations from the mean (half-way of min and max). 
    public static int Next(int min, int max) 
    { 
     double deviations = 3.5; 
     int r; 
     while ((r = (int)BoxMuller(min + (max - min)/2.0, (max - min)/2.0/deviations)) > max || r < min) 
     { 
     } 

     return r; 
    } 

답변

6

박스 뮬러 방법은 "표준"정규 분포를 반환하는 경우, 표준 정규 분포를 변환하기 위해 평균 0, 표준 편차 1을해야합니다, 당신은하여 임의의 숫자를 곱 X가 표준 편차 X를 얻고, 메모리가 올바르게 작동하면 Y를 추가하여 평균 Y를 얻습니다.

보다 공식적인 증거는 Wikipedia article's section on normalizing standard normal variables (property 1)을 참조하십시오. 귀하의 코멘트에 대한 응답으로


은, 엄지 손가락의 규칙은 정규 분포의 99.7 %가 +/- 3 배 표준 편차 내에있을 것입니다. 예를 들어 0에서 100까지의 정규 분포가 필요하다면 평균보다 작을 것이고 SD는 (100/2)/3 = 16.667이됩니다. 따라서 Box-Muller 알고리즘에서 얻은 값은 16.667을 곱하여 배수를 "늘려"50을 더해 "중앙에 배치"하십시오.


존, 당신의 최신 코멘트에 대한 응답으로, 정말 Next 기능의 요점이 무엇인지 확실하지 않다. 항상 표준 편차 1을 사용하며 최소값과 최대 값의 중간 값을 사용합니다.

-X ~ + X 범위의 ~ 99.7 % 인 Y의 평균을 원할 경우 BoxMuller(Y, X/3)을 호출하면됩니다.

+0

예, 이것은 무엇이다 BoxMuller (double mean, double standard_deviation)는 위에서 달성됩니다. 그러나 문제는 Next (int min, int max)가 범위의 절반 정도에 가까운 값을 반환한다는 것입니다. 이는 편차를 정확하게 "계단"하는 방법을 이해할 수 없기 때문입니다. –

+0

3.5 표준 편차의 경우 "return (int) BoxMuller (min + (max - min)/2.0, (max - min)/2.0/3.5)"가됩니다. –

+0

표준 편차의 +/- 3 배는 97 %가 아니라 99.7 %를 제공한다고 말할 수 있습니까? +/- 시그마 : ~ 68 % +/- 2 시그마 : ~ 95 % +/- 3 시그마 : ~ 99.7 % http://en.wikipedia.org/wiki/68-95-99.7_rule – DmitryK

1

음, -2 * 시그마 .. +2 * 시그마는 벨 커브의 95 %를 제공합니다. (이미 언급 한 위키 문서의 "표준 편차 및 신뢰 구간"섹션을 확인하십시오).

그래서이 작품 수정 :

return (int)BoxMuller(min + (max - min)/2.0, 1.0); 

를 2.0 1.0 (표준 편차)을 변경 (또는 더 이상의 95 % 적용을 원하는 경우)

return (int)BoxMuller(min + (max - min)/2.0, 2.0); 
+0

이제 저는 여러분에게 고맙게 생각하고 싶은 것을 이해합니다. -2 * 시그마 .. + 2 * 시그마가 범위 (분, 최대)의 시작과 끝이되도록하고 싶습니다. –

+0

아, 이제 이해합니다. 따라서 평균값 왼쪽과 오른쪽에서 빠져 나와 95 % 신뢰도로 min 또는 max를 "히트"하려고합니다. 이 경우 - 평균값을 유지하므로 (최소 + (최대 - 최소)/2) 시그마 (표준 편차)를 계산해야합니다. 2 * 시그마로 스텝 아웃하면 95 % 간격이됩니다. 따라서이 간격의 길이는 4 * 시그마입니다. 그러나 (max-min)으로 계산할 수도 있습니다. 그것은 우리에게 시그마 = (최대 - 최소)/4를줍니다. 시도해 볼 수 있습니까? – DmitryK

+0

95 % 신뢰도로 min..max 범위 내에서 "hit"합니다. 정확하게 말하면됩니다. – DmitryK