2 복식 사이에 난수를 생성 할 수 있습니까?
예:
public double GetRandomeNumber(double minimum, double maximum)
{
return Random.NextDouble(minimum, maximum)
}
그런 다음 다음과 같이 호출합니다.
double result = GetRandomNumber(1.23, 5.34);
모든 의견을 부탁드립니다.
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가 정확히 동일한 타임 스탬프를 시드하고 동일한 난수 스트림을 생성합니다.
public double GetRandomNumber(this Random random, double minimum, double maximum) {...}
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));
}
이 방법을 사용하면 다른 이중 값을 얻을 수 있습니다.
나는 파티에 약간 늦었지만 일반적인 솔루션을 구현해야했으며 솔루션 중 어느 것도 내 요구를 충족시킬 수 없다는 것이 밝혀졌습니다.
허용되는 솔루션은 작은 범위에 적합합니다. 그러나 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 ushort.MaxValue
에서 "합리적인"최소값 인 10.78294704 ( ulong
범위의 경우 최소값은 3.03518E + 15; int
: 353341) 인 "정확한"상태임을 나타냅니다. 서로 다른 규모로 표시되는 두 전략의 결과는 동일합니다.
편집하다:
최근에 나는 라이브러리를 오픈 소스 로 만들었고 RandomExtensions.NextDouble
, 완전한 검증으로 메소드를 자유롭게 볼 수 있습니다.
값 중 하나가 음수이면 어떻게됩니까? 더 좋은 아이디어는 아닙니다 :
double NextDouble(double min, double max)
{
if (min >= max)
throw new ArgumentOutOfRangeException();
return random.NextDouble() * (Math.Abs(max-min)) + min;
}
Math.Abs()
중복 적이 라고 생각한다 . 당신이를 보장하기 때문에 min >= max
, 다음 max - min
어쨌든 음수가 아닌 번호를해야합니다.
[ 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;
}
}
}
루프에서 호출하면 동일한 난수를 생성하는 방법은 루프 외부의 새 Random () 객체를 전역 변수로 선언하는 것입니다.
루프에서 이것을 실행하려면 GetRandomInt 함수 외부에서 Random 클래스의 인스턴스를 선언해야합니다.
"왜 이런거야?" 물어.
랜덤 클래스는 실제로 의사 난수를 생성하는데, 랜덤 화기의 "시드"는 시스템 시간입니다. 루프가 충분히 빠르면 시스템 클럭 시간이 임의 화기와 다르게 표시되지 않으며 Random 클래스의 각 새 인스턴스는 동일한 시드로 시작하여 동일한 의사 난수를 제공합니다.
출처는 다음과 같습니다 : http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/
정적 랜덤을 사용하거나 시스템 클럭이 시드되어 있기 때문에 숫자는 타이트 / 빠른 루프로 반복되는 경향이 있습니다.
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