Случайное число между двумя двойными номерами
Можно ли сгенерировать случайное число между двумя двойными числами?
Пример:
public double GetRandomeNumber(double minimum, double maximum)
{
return Random.NextDouble(minimum, maximum)
}
Затем я называю это следующим:
double result = GetRandomNumber(1.23, 5.34);
Любые мысли будут оценены.
Ответы
Ответ 1
Да.
Random.NextDouble возвращает double между 0 и 1. Затем вы умножаете это на диапазон, в который вы должны пойти (разница между максимумом и минимумом), а затем добавьте его к базе (минимум).
public double GetRandomNumber(double minimum, double maximum)
{
Random random = new Random();
return random.NextDouble() * (maximum - minimum) + minimum;
}
Реальный код должен быть случайным, являющимся статическим членом. Это позволит сэкономить затраты на создание генератора случайных чисел и позволит вам часто вызывать GetRandomNumber. Поскольку мы инициализируем новый RNG с каждым вызовом, если вы вызываете достаточно быстро, чтобы системное время не менялось между вызовами, RNG будет засеиваться с той же временной меткой и генерировать тот же поток случайных чисел.
Ответ 2
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
и повторно используйте его.
Ответ 3
Простейший подход просто породил бы случайное число между 0 и разностью двух чисел. Затем добавьте меньший из двух чисел в результат.
Ответ 4
Обратите внимание: если вы генерируете random
внутри цикла, как, например, for(int i = 0; i < 10; i++)
, не помещайте объявление new Random()
внутри цикла.
От MSDN:
Генерация случайного числа начинается с начального значения. Если то же самое seed используется многократно, генерируется одна и та же серия чисел. Один способ получения различных последовательностей состоит в том, чтобы сделать начальное значение зависит от времени, тем самым создавая разные серии с каждым новым экземпляр 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));
}
Таким образом, у вас есть гарантия, что вы получите разные двойные значения.
Ответ 5
Вы можете использовать такой код:
public double getRandomNumber(double minimum, double maximum) {
return minimum + randomizer.nextDouble() * (maximum - minimum);
}
Ответ 6
Вы можете сделать это:
public class RandomNumbers : Random
{
public RandomNumbers(int seed) : base(seed) { }
public double NextDouble(double minimum, double maximum)
{
return base.NextDouble() * (maximum - minimum) + minimum;
}
}
Ответ 7
Что делать, если одно из значений отрицательное? Не лучше было бы:
double NextDouble(double min, double max)
{
if (min >= max)
throw new ArgumentOutOfRangeException();
return random.NextDouble() * (Math.Abs(max-min)) + min;
}
Ответ 8
Если вам нужно случайное число в диапазоне [ 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;
}
}
}
Ответ 9
Я немного опоздал на вечеринку, но мне нужно было реализовать общее решение, и оказалось, что ни одно из решений не может удовлетворить мои потребности.
Принятое решение хорошо для небольших диапазонов; однако 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
. Но это порождает другую "проблему", которая хорошо представлена в этом посте: если мы используем такие большие диапазоны, значения могут показаться слишком "неестественными". Например, после генерации 10000 случайных двойных значений от 0 до 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);
}
Некоторые тесты:
Вот отсортированные результаты генерации 10000 случайных двойных чисел от 0 до Double.MaxValue
с обеими стратегиями. Результаты отображаются с использованием логарифмической шкалы:
![0..Double.MaxValue]()
Хотя линейные случайные значения на первый взгляд кажутся неправильными, статистика показывает, что ни одно из них не "лучше", чем другое: даже линейная стратегия имеет равномерное распределение, и среднее различие между значениями практически одинаково с обеими стратегиями..
Игра с разными диапазонами показала мне, что линейная стратегия становится "вменяемой" с диапазоном от 0 до ushort.MaxValue
с "разумным" минимальным значением 10,78294704.
(для диапазона ulong
минимальное значение было 3,03518E + 15; int
: 353341). Это одинаковые результаты обеих стратегий, отображаемые в разных масштабах:
![0..UInt16.MaxValue]()
Изменить:
Недавно я сделал библиотеки с открытым исходным кодом, не стесняйтесь увидеть метод RandomExtensions.NextDouble
с полной проверкой.
Ответ 10
О создании одного и того же случайного числа, если вы вызываете его в цикле, отличным решением является объявление нового объекта Random() вне цикла как глобальной переменной.
Обратите внимание, что вы должны объявить свой экземпляр класса Random вне функции GetRandomInt, если вы собираетесь запускать это в цикле.
"Почему это?" вы спрашиваете.
Ну, класс Random фактически генерирует псевдослучайные числа, а "семя" для рандомизатора является системным временем. Если ваш цикл достаточно быстр, время работы системы не будет отличаться от рандомизатора, и каждый новый экземпляр класса Random начнет с того же семестра и даст вам одно и то же псевдослучайное число.
Источник находится здесь: http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/
Ответ 11
Используйте статический случайный случай или числа будут повторяться в тесных/быстрых циклах из-за того, что системные часы их засевают.
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
Ответ 12
Random random = new Random();
double NextDouble(double minimum, double maximum)
{
return random.NextDouble()*random.Next(minimum,maximum);
}