Frage

Ich würde gerne eine zufällige Zahl wie diese haben: (in C#)

Random r = new Random();
r.next (0,10)

Aber es ist wichtig, dass die Zufallszahl nahe 8 ist (oder normalerweise groß ist), ich meine, wenn wir ein für:

for (int i =0; i<...;i++)
{
  write: r.next (0,10)
}

Das Ergebnis ist so;

8 7 6 9 1 0 5 3 2
2 3 8 9 7 7 6 2 3
8 8 9 7 2 8 2 8 4
3
War es hilfreich?

Lösung

Sie benötigen eine Verteilungsfunktion, die eine Zahl zwischen 0 und 1 erfordert und sie in eine Zahl in dem gewünschten Bereich umwandelt, mit einem höheren Gewicht auf einer bestimmten Zahl. Sie könnten eine solche Funktion mit trigonometrischen Funktionen (sin, cos, ...), exponentiell oder vielleicht einem Polynom erstellen.

Update: Schauen Sie sich an diese Seite Weitere Informationen zur Wahrscheinlichkeitsverteilung

Andere Tipps

Sie müssen Ihre Ergebnisse gewichten. Sie können das mit so etwas tun:

private int[] _distribution = new int[] { 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9 };
Random _r = new Random();

public int GetWeightedRandom()
{
    return _distribution[_r.Next(0, _distribution.Length)];
}

Wenn ich wüsste, dass meine Reichweite klein und konsequent war, würde ich den Tisch verwenden - es ist trivial, es zu einer eigenen Klasse zu machen.

Für die Vollständigkeit werde ich diese Klasse auch in diese Klasse hinzufügen. Diese Klasse leiht sich von der Bildverarbeitung aus und verwendet die Gamma -Korrekturfunktion: Ein Wert zwischen 0 und 1, der auf Gamma erhöht wird, der einen Wert zwischen 0 und 1 zurückgibt, aber mehr auf das niedrige Ende verteilt ist Wenn Gamma <1,0 und mehr bis zum oberen Ende, wenn Gamma> 1,0.

public class GammaRandom {
    double _gamma;
    Random _r;

    public GammaRandom(double gamma) {
        if (gamma <= 0) throw new ArgumentOutOfRangeException("gamma");
        _gamma = gamma;
        _r = new Random();
    }
    public int Next(int low, int high) {
       if (high <= low) throw new ArgumentOutOfRangeException("high");
       double rand = _r.NextDouble();
       rand = math.Pow(rand, _gamma);
       return (int)((high - low) * rand) + low;
    }
}

(Aus Kommentaren, bewegt R aus GetweightedRandom (). Auch die Reichweite der Reichweite zu Next () hinzugefügt)

Ok, lass uns hier wirklich in die Stadt gehen. Ich kanalisiere John Skeet dafür - es ist eine abstrakte Klasse mit einer Vorlageneigenschaft, die eine Transformationsfunktion zurückgibt, die den Bereich [0..1) auf [0..1) ordnet und die Zufallszahl zu diesem Bereich skaliert. Ich habe Gamma auch in Bezug darauf neu implementiert und auch Sünde und COS implementiert.

public abstract class DelegatedRandom
{
    private Random _r = new Random();
    public int Next(int low, int high)
    {
        if (high >= low)
            throw new ArgumentOutOfRangeException("high");
        double rand = _r.NextDouble();
        rand = Transform(rand);
        if (rand >= 1.0 || rand < 0) throw new Exception("internal error - expected transform to be between 0 and 1");
        return (int)((high - low) * rand) + low;
    }
    protected abstract Func<double, double> Transform { get; }
}

public class SinRandom : DelegatedRandom
{
    private static double pihalf = Math.PI / 2;
    protected override Func<double, double> Transform
    {
        get { return r => Math.Sin(r * pihalf); }
    }
}
public class CosRandom : DelegatedRandom
{
    private static double pihalf = Math.PI / 2;
    protected override Func<double, double> Transform
    {
        get { return r => Math.Cos(r * pihalf); }
    }
}
public class GammaRandom : DelegatedRandom
{
    private double _gamma;
    public GammaRandom(double gamma)
    {
        if (gamma <= 0) throw new ArgumentOutOfRangeException("gamma");
        _gamma = gamma;
    }
    protected override Func<double, double> Transform
    {
        get { return r => Math.Pow(r, _gamma); }
    }
}

Anstatt die Array -Variante zu verwenden, können Sie sich dies auch ansehen Also antworte welches einen Link zu haben zu Math.net Iridium Das implementiert ungleichmäßige Zufallsgeneratoren.

Die Vorteile der Array -Variante sind, dass Sie einen dynamischeren Ansatz erhalten, ohne das Array ständig neu schreiben zu müssen. Sie könnten auch einige Dinge tun, die mit der Array-Variante (große ungleichmäßige Zufallszahlen) praktisch unmöglich wären.

Mit einer zusätzlichen Gewichtung sollte dies möglich sein. Hängt davon ab, wie Sie "nahe acht" angeben. Eine sehr einfache Möglichkeit, dies zu tun, ist Folgendes:

for (int i =0; i<...;i++)
{
    n = r.next (0,100);
    write: (n*n) / 1000
}

Das Quadrat wiegt die Zahlen bis zum unteren Ende, dh in diesem Fall werden Sie 33% der Fälle erhalten 0, während du eine bekommst 9 Nur etwa 5% der Fälle.

Diese Methode wird natürlich an den speziellen Fall angepasst.

Nicht genau das, wonach Sie suchen, aber eine sehr einfache Möglichkeit, eine Normalverteilung der Zahlen zu approximieren, besteht darin, mehrere Generationen zusammen hinzuzufügen.

Ein klassisches Beispiel für diese Technik ist im Spiel Dungeons und Drachen, bei denen eine Stärke einer Charaktere durch das Rollen von drei Sechs -Seiten -Würfeln und das Hinzufügen der Ergebnisse bestimmt werden kann. Dies gibt eine Reichweite von 3 bis 18 mit Zahlen um 10 am wahrscheinlichsten. Zu den Varianten gehören:

  • 4 Würfel rollen und den niedrigsten wegwerfen. Dies verdrängt die Verteilung auf höhere Zahlen.
  • Mittelung der Punktzahlen, anstatt sie hinzuzufügen. Dies erleichtert das Verständnis des Ausgangsbereichs.

Alternative, Dies ist ziemlich nah ...

Es sieht für mich so aus, als ob Sie möchten, dass Ihre Zufallszahlen in Richtung des High -Ends gewichtet werden - wäre dies eine faire Bewertung?

Etwas wie Dies kann Ihnen helfen (es ist Java, aber die Prinzipien gelten)

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