[C#] 두 개의 두 숫자 사이의 난수

2 복식 사이에 난수를 생성 할 수 있습니까?

예:

public double GetRandomeNumber(double minimum, double maximum)
{
    return Random.NextDouble(minimum, maximum)
}

그런 다음 다음과 같이 호출합니다.

double result = GetRandomNumber(1.23, 5.34);

모든 의견을 부탁드립니다.



답변

예.

Random.NextDouble은 0과 1 사이의 배가를 반환합니다. 그런 다음 그 범위에 곱할 수있는 범위 (최대 값과 최소값의 차이)를 곱한 다음 기본 (최소)에 더합니다.

public double GetRandomNumber(double minimum, double maximum)
{
    Random random = new Random();
    return random.NextDouble() * (maximum - minimum) + minimum;
}

실제 코드는 임의의 정적 멤버 여야합니다. 이렇게하면 난수 생성기 생성 비용이 절약되고 GetRandomNumber를 매우 자주 호출 할 수 있습니다. 모든 통화에서 새로운 RNG를 초기화하기 때문에 시스템 시간이 통화간에 변경되지 않을 정도로 빠르게 전화를 걸면 RNG가 정확히 동일한 타임 스탬프를 시드하고 동일한 난수 스트림을 생성합니다.


답변

Johnny5는 확장 메소드 작성을 제안했습니다. 이 작업을 수행하는 방법을 보여주는보다 완전한 코드 예제는 다음과 같습니다.

public static class RandomExtensions
{
    public static double NextDouble(
        this Random random,
        double minValue,
        double maxValue)
    {
        return random.NextDouble() * (maxValue - minValue) + minValue;
    }
}

이제 Random클래스 의 메소드 인 것처럼 호출 할 수 있습니다 .

Random random = new Random();
double value = random.NextDouble(1.23, 5.34);

Random루프에서 많은 수의 새로운 객체를 생성해서는 안된다는 것을 의미합니다. 왜냐하면 동일한 값을 여러 번 연속해서 얻을 수 있기 때문입니다. 많은 난수가 필요한 경우 하나의 인스턴스를 만들어 Random재사용하십시오.


답변

조심하십시오 : random예를 들어 내부 루프를 생성하는 경우 루프 안에 선언을 for(int i = 0; i < 10; i++)넣지 마십시오 new Random().

에서 MSDN :

난수 생성은 시드 값에서 시작합니다. 동일한 시드가 반복적으로 사용되면 동일한 일련의 숫자가 생성됩니다. 다른 시퀀스를 생성하는 한 가지 방법은 시드 값을 시간에 따라 다르게하여 새로운 각 인스턴스 인 Random에 대해 다른 시리즈를 생성하는 것입니다. 기본적으로 Random 클래스의 매개 변수가없는 생성자는 시스템 시계를 사용하여 시드 값을 생성합니다 …

따라서이 사실을 바탕으로 다음과 같이하십시오.

var random = new Random();

for(int d = 0; d < 7; d++)
{
    // Actual BOE
    boes.Add(new LogBOEViewModel()
    {
        LogDate = criteriaDate,
        BOEActual = GetRandomDouble(random, 100, 1000),
        BOEForecast = GetRandomDouble(random, 100, 1000)
    });
}

double GetRandomDouble(Random random, double min, double max)
{
     return min + (random.NextDouble() * (max - min));
}

이 방법을 사용하면 다른 이중 값을 얻을 수 있습니다.


답변

가장 간단한 방법은 단순히 0과 두 숫자의 차이 사이의 난수를 생성하는 것입니다. 그런 다음 두 숫자 중 작은 숫자를 결과에 추가하십시오.


답변

다음과 같은 코드를 사용할 수 있습니다.

public double getRandomNumber(double minimum, double maximum) {
    return minimum + randomizer.nextDouble() * (maximum - minimum);
}


답변

당신은 이것을 할 수 있습니다 :

public class RandomNumbers : Random
{
    public RandomNumbers(int seed) : base(seed) { }

    public double NextDouble(double minimum, double maximum)
    {
        return base.NextDouble() * (maximum - minimum) + minimum;
    }
}


답변

나는 파티에 약간 늦었지만 일반적인 솔루션을 구현해야했으며 솔루션 중 어느 것도 내 요구를 충족시킬 수 없다는 것이 밝혀졌습니다.

허용되는 솔루션은 작은 범위에 적합합니다. 그러나 maximum - minimum넓은 범위에서는 무한대가 될 수 있습니다. 따라서 수정 된 버전은이 버전이 될 수 있습니다.

public static double NextDoubleLinear(this Random random, double minValue, double maxValue)
{
    // TODO: some validation here...
    double sample = random.NextDouble();
    return (maxValue * sample) + (minValue * (1d - sample));
}

이도 사이 좋게 난수를 생성 double.MinValue하고 double.MaxValue. 그러나 이것은 또 다른 “문제”를 소개합니다 . 이것은이 글에서 훌륭하게 제시 됩니다 : 만약 우리가 그러한 큰 범위를 사용한다면 그 가치는 너무 부자연 스럽습니다. 예를 들어, 0과 10,000 사이의 임의의 배가 10,000을 생성 한 후 double.MaxValue모든 값은 2.9579E + 304와 1.7976E + 308 사이입니다.

그래서 나는 또 다른 버전을 만들었습니다.이 버전은 로그 스케일로 숫자를 생성합니다.

public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue)
{
    // TODO: some validation here...
    bool posAndNeg = minValue < 0d && maxValue > 0d;
    double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue));
    double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));

    int sign;
    if (!posAndNeg)
        sign = minValue < 0d ? -1 : 1;
    else
    {
        // if both negative and positive results are expected we select the sign based on the size of the ranges
        double sample = random.NextDouble();
        var rate = minAbs / maxAbs;
        var absMinValue = Math.Abs(minValue);
        bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample;
        sign = isNeg ? -1 : 1;

        // now adjusting the limits for 0..[selected range]
        minAbs = 0d;
        maxAbs = isNeg ? absMinValue : Math.Abs(maxValue);
    }

    // Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because
    // that would cause too many almost zero results, which are much smaller than the original NextDouble values.
    double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d);
    double maxExponent = Math.Log(maxAbs, 2d);
    if (minExponent == maxExponent)
        return minValue;

    // We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0
    if (maxExponent < minExponent)
        minExponent = maxExponent - 4;

    double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent));

    // protecting ourselves against inaccurate calculations; however, in practice result is always in range.
    return result < minValue ? minValue : (result > maxValue ? maxValue : result);
}

일부 테스트 :

다음은 0과 Double.MaxValue두 전략 모두에서 10,000 개의 임의의 이중 숫자를 생성 한 정렬 결과입니다 . 결과는 로그 스케일을 사용하여 표시됩니다.

0 .. 더블 최대 값

선형 랜덤 값이 언뜻보기에는 잘못된 것 같지만 통계에 따르면 이들 중 어느 것도 다른 것보다 “더 나은”것이 없음을 보여줍니다. 선형 전략조차도 균등 한 분포가 있으며 값 간의 평균 차이는 두 전략과 거의 동일합니다 .

다른 범위를 가지고 노는 것은 선형 전략이 0 ushort.MaxValue에서 “합리적인”최소값 인 10.78294704 ( ulong범위의 경우 최소값은 3.03518E + 15; int: 353341) 인 “정확한”상태임을 나타냅니다. 서로 다른 규모로 표시되는 두 전략의 결과는 동일합니다.

0..UInt16.MaxValue


편집하다:

최근에 나는 라이브러리를 오픈 소스 로 만들었고 RandomExtensions.NextDouble, 완전한 검증으로 메소드를 자유롭게 볼 수 있습니다.