두 개의 두 숫자 사이의 난수


156

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

예:

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

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

double result = GetRandomNumber(1.23, 5.34);

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

답변:


329

예.

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

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

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


33
반복해서 동일한 값을 생성하므로 루프에서 GetRandomNumber ()를 호출하면 조심하십시오
John Rasch

13
훌륭한 확장 방법이 될 수 있습니다.public double GetRandomNumber(this Random random, double minimum, double maximum) {...}
Johnny5

5
Random.NextDouble은 1.0을 반환하지 않으므로이 함수는 절대 최대 수와 같지 않습니다.
Matthew

6
시드로 새로운 Random ((int) DateTime.Now.Ticks)을 넣는 것이 좋습니다. 빠른 루프에서도 "더 무작위"로 만들어야합니다.
Daniel Skowroński

5
최소값이 double.MinValue이고 최대 값이 double.MaxValue 인 경우에는 작동하지 않습니다. 이 사용 사례를 처리하는 방법에 대한 제안 사항이 있습니까?
유전자 S

40

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재사용하십시오.


9

조심하십시오 : 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));
}

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


8

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


3

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

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

2

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

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

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

2

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

허용되는 솔루션은 작은 범위에 적합합니다. 그러나 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, 완전한 검증으로 메소드를 자유롭게 볼 수 있습니다.


1

값 중 하나가 음수이면 어떻게됩니까? 더 좋은 아이디어는 아닙니다 :

double NextDouble(double min, double max)
{
       if (min >= max)
            throw new ArgumentOutOfRangeException();    
       return random.NextDouble() * (Math.Abs(max-min)) + min;
}

5
나는 이것이 Math.Abs()중복 적이 라고 생각한다 . 당신이를 보장하기 때문에 min >= max, 다음 max - min어쨌든 음수가 아닌 번호를해야합니다.
Brian Reischl

1

[ double.MinValue; 범위의 난수가 필요한 경우 double.MaxValue]

// Because of:
double.MaxValue - double.MinValue == double.PositiveInfinity

// This will be equals to NaN or PositiveInfinity
random.NextDouble() * (double.MaxValue - double.MinValue)

대신 사용하십시오 :

public static class RandomExtensions
{
    public static double NextDoubleInMinMaxRange(this Random random)
    {
        var bytes = new byte[sizeof(double)];
        var value = default(double);
        while (true)
        {
            random.NextBytes(bytes);
            value = BitConverter.ToDouble(bytes, 0);
            if (!double.IsNaN(value) && !double.IsInfinity(value))
                return value;
        }
    }
}

2
여기에 두 번째 예에서와 같은 비대칭 분포 좋은 지적하지만,이 제안의 결과 stackoverflow.com/a/3365388/3922292
표트르 Falkowski

0

루프에서 호출하면 동일한 난수를 생성하는 방법은 루프 외부의 새 Random () 객체를 전역 변수로 선언하는 것입니다.

루프에서 이것을 실행하려면 GetRandomInt 함수 외부에서 Random 클래스의 인스턴스를 선언해야합니다.

"왜 이런거야?" 물어.

랜덤 클래스는 실제로 의사 난수를 생성하는데, 랜덤 화기의 "시드"는 시스템 시간입니다. 루프가 충분히 빠르면 시스템 클럭 시간이 임의 화기와 다르게 표시되지 않으며 Random 클래스의 각 새 인스턴스는 동일한 시드로 시작하여 동일한 의사 난수를 제공합니다.

출처는 다음과 같습니다 : http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/


이것은 OP의 실제 질문에 대답조차하지 않기 때문에 주석으로 더 적합합니다.
b1nary.atr0phy 1

0

정적 랜덤을 사용하거나 시스템 클럭이 시드되어 있기 때문에 숫자는 타이트 / 빠른 루프로 반복되는 경향이 있습니다.

public static class RandomNumbers
{
    private static Random random = new Random();
    //=-------------------------------------------------------------------
    // double between min and the max number
    public static double RandomDouble(int min, int max) 
    {
        return (random.NextDouble() * (max - min)) + min;
    }
    //=----------------------------------
    // double between 0 and the max number
    public static double RandomDouble(int max) 
    {
        return (random.NextDouble() * max);
    }
    //=-------------------------------------------------------------------
    // int between the min and the max number
    public static int RandomInt(int min, int max) 
    {   
        return random.Next(min, max + 1);
    }
    //=----------------------------------
    // int between 0 and the max number
    public static int RandomInt(int max) 
    {
        return random.Next(max + 1);
    }
    //=-------------------------------------------------------------------
 }

참조 : https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netframework-4.8


-1
Random random = new Random();

double NextDouble(double minimum, double maximum)
{  

    return random.NextDouble()*random.Next(minimum,maximum);

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.