문제

다음과 같은 임의의 숫자를 원합니다 : (C#)

Random r = new Random();
r.next (0,10)

그러나 임의의 숫자가 더 가까워지면 (또는 보통 큽니다), 우리가 a를 사용하는 경우를 의미합니다.

for (int i =0; i<...;i++)
{
  write: r.next (0,10)
}

결과는 다음과 같습니다.

8 7 6 9 1 0 5 3 2
2 3 8 9 7 7 6 2 3
8 8 9 7 2 8 2 8 4
3
도움이 되었습니까?

해결책

0과 1 사이의 숫자를 취하고 특정 숫자에서 더 높은 가중치로 원하는 범위의 숫자로 변환하는 분포 함수가 필요합니다. 삼각 함수 (sin, cos, ...), 지수 또는 다항식으로 이러한 함수를 만들 수 있습니다.

업데이트 : 살펴보십시오 이 페이지 확률 분포에 대한 자세한 내용

다른 팁

결과를 가중시켜야합니다. 당신은 다음과 같이 할 수 있습니다.

private int[] _distribution = new int[] { 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9 };
Random _r = new Random();

public int GetWeightedRandom()
{
    return _distribution[_r.Next(0, _distribution.Length)];
}

내 범위가 작고 일관성이 있다는 것을 알았다면, 나는 테이블을 사용할 것입니다. 자체 수업을 만드는 것은 사소한 일입니다.

완전성을 위해이 클래스를 추가하겠습니다.이 클래스는 이미지 처리에서 차용하고 감마 수정 기능을 사용합니다. 0과 1 사이의 값은 0과 1 사이의 값을 반환하지만 로우 엔드에 더 많이 분산됩니다. gamma <1.0 이상인 경우 gamma> 1.0 인 경우.

public class GammaRandom {
    double _gamma;
    Random _r;

    public GammaRandom(double gamma) {
        if (gamma <= 0) throw new ArgumentOutOfRangeException("gamma");
        _gamma = gamma;
        _r = new Random();
    }
    public int Next(int low, int high) {
       if (high <= low) throw new ArgumentOutOfRangeException("high");
       double rand = _r.NextDouble();
       rand = math.Pow(rand, _gamma);
       return (int)((high - low) * rand) + low;
    }
}

(댓글에서 getweightedrandom ()에서 r을 옮겼습니다. 또한 다음 ()에 범위 확인 범위를 추가했습니다.

좋아, 정말로 여기 마을에 가자. 나는 이것을 위해 John Skeet를 채널로 만들고있다 - 그것은 범위 [0..1)을 [0..1)로 매핑하고 임의의 숫자를 해당 범위로 조정하는 변환 함수를 반환하는 템플릿 속성을 갖춘 추상 클래스입니다. 나는 또한 감마를 그것을 다시 구현하고 죄와 COS도 구현했다.

public abstract class DelegatedRandom
{
    private Random _r = new Random();
    public int Next(int low, int high)
    {
        if (high >= low)
            throw new ArgumentOutOfRangeException("high");
        double rand = _r.NextDouble();
        rand = Transform(rand);
        if (rand >= 1.0 || rand < 0) throw new Exception("internal error - expected transform to be between 0 and 1");
        return (int)((high - low) * rand) + low;
    }
    protected abstract Func<double, double> Transform { get; }
}

public class SinRandom : DelegatedRandom
{
    private static double pihalf = Math.PI / 2;
    protected override Func<double, double> Transform
    {
        get { return r => Math.Sin(r * pihalf); }
    }
}
public class CosRandom : DelegatedRandom
{
    private static double pihalf = Math.PI / 2;
    protected override Func<double, double> Transform
    {
        get { return r => Math.Cos(r * pihalf); }
    }
}
public class GammaRandom : DelegatedRandom
{
    private double _gamma;
    public GammaRandom(double gamma)
    {
        if (gamma <= 0) throw new ArgumentOutOfRangeException("gamma");
        _gamma = gamma;
    }
    protected override Func<double, double> Transform
    {
        get { return r => Math.Pow(r, _gamma); }
    }
}

배열 변형을 사용하는 대신 이것을 볼 수도 있습니다. 그러니 대답 링크가 있습니다 Math.net Iridium 이는 불균일 무작위 생성기를 구현합니다.

배열 변형의 장점은 배열을 항상 다시 작성하지 않고도 더 역동적 인 접근 방식을 얻는 것입니다. 배열 변형 (큰 불균일 랜덤 숫자)으로 실제로 불가능할 수있는 일을 할 수도 있습니다.

어떤 종류의 추가 가중치를 사용하면 가능해야합니다. "가까운 8"을 지정하는 방법에 따라 다릅니다. 매우 간단한 방법은 다음과 같습니다.

for (int i =0; i<...;i++)
{
    n = r.next (0,100);
    write: (n*n) / 1000
}

제곱의 무게는 저쪽 끝으로 숫자를 측정합니다. 즉,이 경우에는 33%가 0, 당신은 얻을 수 있습니다 9 시간의 약 5%에 불과합니다.

이 방법은 물론 특정 사례에 맞게 조정됩니다.

정확히 당신이 찾고있는 것이 아니라 정규 분포를 근사화하는 매우 간단한 방법은 여러 세대를 함께 추가하는 것입니다.

이 기술의 전형적인 예는 게임 던전과 드래곤 게임에 있습니다. 이것은 최대 약 10의 숫자로 3 ~ 18의 범위를 제공합니다. 변형은 다음을 포함합니다.

  • 4 개의 주사위를 굴리고 가장 낮은 것을 버립니다. 이것은 더 높은 숫자로의 분포를 왜곡시킵니다.
  • 점수를 추가하기보다는 점수를 평균화합니다. 이로 인해 출력 범위를 쉽게 이해할 수 있습니다.

대안 적으로, 이것 꽤 가깝습니다 ...

임의의 숫자가 하이 엔드를 향해 가중치를주고 싶어하는 것처럼 보입니다. 이것이 공정한 평가일까요?

같은 것 이것 당신을 도울 수 있습니다 (Java이지만 원칙은 적용됩니다)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top