Frage

Gibt es eine Klasse in der Standardbibliothek von .NET, die mir die Funktionalität gibt Zufallsvariablen zu erstellen, die Gauß-Verteilung folgen?

War es hilfreich?

Lösung

Jarrett Vorschlag der Verwendung eines Box-Muller ist für eine schnelle und unsaubere Lösung gut zu transformieren. Eine einfache Implementierung:

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)

Andere Tipps

erscheint diese Frage auf Google für .NET-Gauß-Generation bewegt zu haben, so dass ich dachte ich eine Antwort schreiben würde.

Ich habe einige Erweiterungsmethoden für die .NET-Klasse Random gemacht, einschließlich einer Implementierung die Box-Muller-Transformation. Da sie Erweiterungen sind, solange das Projekt enthalten (oder verweisen Sie auf die kompilierte DLL), können Sie noch tun

var r = new Random();
var x = r.NextGaussian();

Hope niemand etwas dagegen die schamlose Werbung.

Beispiel Histogramm der Ergebnisse (eine Demo-Anwendung für diese Zeichnung ist im Preis inbegriffen):

eingeben Bild Beschreibung hier

Math.NET bietet diese Funktionalität. Hier ist, wie:

double mean = 100;
double stdDev = 10;

MathNet.Numerics.Distributions.Normal normalDist = new Normal(mean, stdDev);
double randomGaussianValue=   normalDist.Sample();

Hier finden Sie Dokumentation hier: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm

Ich habe eine Anfrage für eine solche Funktion auf Microsoft Connect. Ist dies etwas ist, die Sie suchen, stimmen Sie dafür, und ihre Sichtbarkeit erhöhen.

https://connect.microsoft. com / Visual Studio / Feedback / details / 634.346 / Gauß--normal-Verteilung Zufallszahlen

Diese Funktion wird in dem Java-SDK enthalten. Seine Umsetzung ist verfügbar als Teil die Dokumentation und wird in C # oder einer anderen .NET-Sprachen leicht portiert.

Wenn Sie sich für die reine Geschwindigkeit suchen, ist das Zigorat Algorithmus wird im Allgemeinen als das anerkannt schnellster Ansatz.

Ich bin kein Experte zu diesem Thema, obwohl - ich über die Notwendigkeit dazu kam, während ein Partikelfilter für meine RoboCup 3D simulierte Roboter-Fußball-Bibliothek und war überrascht, als dies war nicht im Rahmen enthalten.


In der Zwischenzeit, hier ist ein Wrapper für Random, die eine effiziente Umsetzung der Box Muller polar Verfahren sieht vor:

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;
    }
}

Math.NET Iridium behauptet auch, „nicht einheitliche Zufallsgeneratoren (normal, poisson, binomische zu implementieren, ...)“.

Hier ist eine weitere schnelle und schmutzige Lösung zur Erzeugung von Zufallsvariablen, die normalverteilt . Er zieht einigen zufälligen Punkt (x, y) und prüft, ob dieser Punkt unter der Kurve der Wahrscheinlichkeitsdichtefunktion liegt, sonst wiederholen.

Bonus: Sie können Zufallsvariablen für jede andere Verteilung erzeugen (zB Exponentialverteilung oder poisson-Verteilung ) nur durch die Dichtefunktion zu ersetzen.

    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 * σ * σ));
    }

Wichtig: Wählen Sie das Intervall von y und die Parameter σ und μ , so dass die Kurve der Funktion nicht Cutoff ist es maximal ist / Minimalpunkte (beispielsweise bei x = Mittelwert). Denken Sie an die Intervalle von x und y als Begrenzungsrahmen, in dem die Kurve passen müssen.

würde Ich mag auf @ yoyoyoyosef Antwort zu erweitern, indem es noch schneller zu machen und eine Wrapper-Klasse zu schreiben. Der Systemaufwand darf nicht doppelt so schnell bedeuten, aber ich denke, es sollte seine fast doppelt so schnell. Es ist nicht Thread-sicher, though.

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();
    }
}

Die Erweiterung auf Drew Noakes Antwort, wenn Sie eine bessere Leistung als Box-Muller (um 50-75% schneller) benötigen, hat Colin Grün eine Implementierung des Ziggurat Algorithmus in C # geteilt, die Sie hier finden:

http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html

Ziggurat verwendet eine Nachschlagtabellenwerte zu behandeln, die ausreichend weit von der Kurve fallen, die es schnell akzeptieren oder abzulehnen. Rund 2,5% der Zeit hat es weitere Berechnungen zu tun, welche Seite der Kurve zu bestimmen, ist eine Zahl auf.

Der Ausbau aus der @Noakes und @ Hameer die Antworten, ich habe implementiert auch eine ‚Gaussian‘ Klasse, aber Speicherplatz zu vereinfachen, habe ich es geschafft ein Kind der Klasse Random so, dass Sie auch die Grund Next () aufrufen können, nextdouble (), usw. aus der Gauß-Klasse als auch ohne ein zusätzliches Random-Objekt zu erstellen, die es zu behandeln. Ich eliminierte auch die _available und _nextgauss globale Klasseneigenschaften, wie ich sie bei Bedarf nicht sehen, da diese Klasse Instanz basiert, soll es Thread-sicher sein, wenn Sie geben jeweils ein eigenes Gaussian Objekt fädeln. Ich zog auch alle die Laufzeit zugeordnet Variablen aus der Funktion und machte ihr Klasseneigenschaften, dies wird die Anzahl der Anrufe an den Speicher-Manager zu reduzieren, da die 4 Doppelzimmer sollten theoretisch nie de-zugewiesen werden, bis das Objekt zerstört wird.

public class Gaussian : Random
{

    private double u1;
    private double u2;
    private double temp1;
    private double temp2;

    public Gaussian(int seed):base(seed)
    {
    }

    public Gaussian() : base()
    {
    }

    /// <summary>
    /// Obtains normally (Gaussian) distrubuted 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 RandomGauss(double mu = 0, double sigma = 1)
    {
        if (sigma <= 0)
            throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");

        u1 = base.NextDouble();
        u2 = base.NextDouble();
        temp1 = Math.Sqrt(-2 * Math.Log(u1));
        temp2 = 2 * Math.PI * u2;

        return mu + sigma*(temp1 * Math.Cos(temp2));
    }
}

Sie könnten versuchen, Infer.NET. Es ist nicht kommerziell noch obwohl lizenziert. Hier wird Link

Es ist ein Wahrscheinlichkeits Rahmen für .NET meine Microsoft Forschung entwickelt. Sie haben .NET-Typen für Verteilungen von Bernoulli, Beta, Gamma, Gaussian, Poisson, und wahrscheinlich einige mehr ich außen vor.

Es kann erreichen, was Sie wollen. Danke.

Dies ist meine einfache Box Muller inspirierte Umsetzung. Sie können die Auflösung erhöhen Ihre Bedürfnisse anzupassen. Obwohl dies für mich funktioniert gut, ist dies eine Annäherung begrenzte Reichweite, so im Auge behalten werden die Schwänze geschlossen und endlich, aber sicherlich können Sie sie erweitern je nach Bedarf.

    //
    // 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;
   }
} 

Ich glaube nicht, es gibt. Und ich hoffe wirklich, es ist nicht, wie der Rahmen bereits aufgebläht ist genug, ohne dass diese speziellen Funktionen füllt es noch mehr.

Hier finden Sie aktuelle http://www.extremeoptimization.com/Statistics /UsersGuide/ContinuousDistributions/NormalDistribution.aspx und http: //www.vbforums .com / showthread.php? t = 488959 für eine dritte .NET-Lösungen though.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top