Есть ли класс в стандартной библиотеке .NET, который дает мне возможность создавать случайные переменные, которые следуют за распределением Гаусса?
Случайные гауссовские переменные
Ответ 1
Предложение Джарретта об использовании преобразования Box-Muller полезно для быстрого и грязного решения. Простая реализация:
Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)
Ответ 2
Этот вопрос, похоже, переместился поверх поколения Google для .NET Gaussian, поэтому я решил, что опубликую ответ.
Я сделал несколько методов расширения для класса .NET Random, включая реализацию преобразования Box-Muller. Поскольку они являются расширениями, если проект включен (или вы ссылаетесь на скомпилированную DLL), вы все равно можете сделать
var r = new Random();
var x = r.NextGaussian();
Надеюсь, что никто не упустит бесстыдную плагин.
Пример гистограммы результатов (демонстрационное приложение для рисования включено):
Ответ 3
http://mathworld.wolfram.com/Box-MullerTransformation.html
Используя две случайные величины, вы можете генерировать случайные значения вдоль распределения Гаусса. Это не сложная задача.
Ответ 4
Math.NET предоставляет эту функциональность. Вот как:
double mean = 100;
double stdDev = 10;
MathNet.Numerics.Distributions.Normal normalDist = new Normal(mean, stdDev);
double randomGaussianValue= normalDist.Sample();
Здесь вы можете найти документацию: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm
Ответ 5
Я создал запрос на такую функцию в Microsoft Connect. Если это то, что вы ищете, проголосуйте за него и увеличьте его видимость.
Эта функция включена в Java SDK. Его реализация доступна как часть документации и легко переносится на С# или другие языки .NET.
Если вы ищете чистую скорость, то алгоритм фильтр частиц для моего RoboCup 3D имитировала роботизированную футбольную библиотеку и была удивлена, когда это не было включено в рамки.
В то же время здесь обертка для Random
, которая обеспечивает эффективную реализацию полярного метода Box Muller:
public sealed class GaussianRandom
{
private bool _hasDeviate;
private double _storedDeviate;
private readonly Random _random;
public GaussianRandom(Random random = null)
{
_random = random ?? new Random();
}
/// <summary>
/// Obtains normally (Gaussian) distributed random numbers, using the Box-Muller
/// transformation. This transformation takes two uniformly distributed deviates
/// within the unit circle, and transforms them into two independently
/// distributed normal deviates.
/// </summary>
/// <param name="mu">The mean of the distribution. Default is zero.</param>
/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>
/// <returns></returns>
public double NextGaussian(double mu = 0, double sigma = 1)
{
if (sigma <= 0)
throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");
if (_hasDeviate)
{
_hasDeviate = false;
return _storedDeviate*sigma + mu;
}
double v1, v2, rSquared;
do
{
// two random values between -1.0 and 1.0
v1 = 2*_random.NextDouble() - 1;
v2 = 2*_random.NextDouble() - 1;
rSquared = v1*v1 + v2*v2;
// ensure within the unit circle
} while (rSquared >= 1 || rSquared == 0);
// calculate polar tranformation for each deviate
var polar = Math.Sqrt(-2*Math.Log(rSquared)/rSquared);
// store first deviate
_storedDeviate = v2*polar;
_hasDeviate = true;
// return second deviate
return v1*polar*sigma + mu;
}
}
Ответ 6
Math.NET Iridium также утверждает, что реализует "неравномерные случайные генераторы (нормальные, пуассонные, биномиальные,...)".
Ответ 7
Я хотел бы расширить ответ на @yoyoyoyosef, сделав это еще быстрее и написание класса-оболочки. Потери накладных расходов могут не означать в два раза быстрее, но я думаю, что это должно быть почти в два раза быстрее. Однако он не является потокобезопасным.
public class Gaussian
{
private bool _available;
private double _nextGauss;
private Random _rng;
public Gaussian()
{
_rng = new Random();
}
public double RandomGauss()
{
if (_available)
{
_available = false;
return _nextGauss;
}
double u1 = _rng.NextDouble();
double u2 = _rng.NextDouble();
double temp1 = Math.Sqrt(-2.0*Math.Log(u1));
double temp2 = 2.0*Math.PI*u2;
_nextGauss = temp1 * Math.Sin(temp2);
_available = true;
return temp1*Math.Cos(temp2);
}
public double RandomGauss(double mu, double sigma)
{
return mu + sigma*RandomGauss();
}
public double RandomGauss(double sigma)
{
return sigma*RandomGauss();
}
}
Ответ 8
Это моя простая вставка Box Muller. Вы можете увеличить разрешение в соответствии с вашими потребностями. Хотя это отлично работает для меня, это ограниченное приближение диапазона, поэтому имейте в виду, что хвосты закрыты и конечны, но, конечно же, вы можете расширить их по мере необходимости.
//
// by Dan
// islandTraderFX
// copyright 2015
// Siesta Key, FL
//
// 0.0 3231 ********************************
// 0.1 1981 *******************
// 0.2 1411 **************
// 0.3 1048 **********
// 0.4 810 ********
// 0.5 573 *****
// 0.6 464 ****
// 0.7 262 **
// 0.8 161 *
// 0.9 59
//Total: 10000
double g()
{
double res = 1000000;
return random.Next(0, (int)(res * random.NextDouble()) + 1) / res;
}
public static class RandomProvider
{
public static int seed = Environment.TickCount;
private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>(() =>
new Random(Interlocked.Increment(ref seed))
);
public static Random GetThreadRandom()
{
return randomWrapper.Value;
}
}
Ответ 9
Развернувшись на Drew Noakes, если вам нужна более высокая производительность, чем Box-Muller (примерно на 50-75% быстрее), Colin Green поделился реализацией алгоритма Зиггурата на С#, который вы можете найти здесь:
http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html
Ziggurat использует таблицу поиска для обработки значений, которые достаточно далеко от кривой, которые она быстро примет или отклонит. Примерно в 2,5% времени он должен выполнить дальнейшие вычисления, чтобы определить, на какой стороне кривой находится число.
Ответ 10
Вот еще одно быстрое и грязное решение для генерации случайных переменных нормальное распространение. Он рисует некоторую случайную точку (x, y) и проверяет, находится ли эта точка под кривой вашей функции плотности вероятности, в противном случае повторяется.
Бонус: вы можете генерировать случайные переменные для любого другого распределения (например, экспоненциальное распределение или распределение пуассонов), просто заменив функцию плотности.
static Random _rand = new Random();
public static double Draw()
{
while (true)
{
// Get random values from interval [0,1]
var x = _rand.NextDouble();
var y = _rand.NextDouble();
// Is the point (x,y) under the curve of the density function?
if (y < f(x))
return x;
}
}
// Normal (or gauss) distribution function
public static double f(double x, double μ = 0.5, double σ = 0.5)
{
return 1d / Math.Sqrt(2 * σ * σ * Math.PI) * Math.Exp(-((x - μ) * (x - μ)) / (2 * σ * σ));
}
Важно: выберите интервал y и параметры σ и μ, чтобы кривая функции не обрезалась в ней с максимальными/минимальными точками (например, при x = средняя). Подумайте об интервалах x и y в качестве ограничивающего прямоугольника, в который должна вписываться кривая.
Ответ 11
Вы можете попробовать Infer.NET. Однако это не коммерческая лицензия. Здесь ссылка
Это вероятностная структура для .NET, которая разработала мои исследования Microsoft. У них есть типы .NET для распределений Бернулли, Бета, Гамма, Гаусса, Пуассона и, возможно, еще некоторые, о которых я забыл.
Он может выполнить то, что вы хотите. Спасибо.
Ответ 12
Я не думаю, что есть. И я действительно надеюсь, что нет, поскольку структура уже достаточно раздута, без такой специализированной функциональности, наполняющей ее еще больше.
Взгляните на http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspx и http://www.vbforums.com/showthread.php?t=488959 для сторонних .NET-решений.