2009-07-31 14 views
7

Chciałbym mieć liczbę losową tak: (w C#)specjalny losowy numer

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

ale ważne jest, aby liczby losowej być bardziej blisko 8 (lub to zazwyczaj duże), Mam na myśli, jeśli użyjemy dla:

Wynik będzie tak;

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 
+5

Więc prosisz dla liczb losowych, które eee, nie są przypadkowe? – blowdart

+12

Nie, on nie chce, on po prostu chce innej dystrybucji (więcej w stylu Gaussa około 8, nierównomiernie rozmieszczonych we wszystkich liczbach) – schnaader

+1

Chciałbym generować ważone liczby losowe. –

Odpowiedz

2

Trzeba funkcję dystrybucyjną, która pobiera liczbę między 0 a 1 i konwertuje go na liczbę w przedziale chcesz, z wyższa waga na określonej liczbie. Tę funkcję można utworzyć za pomocą funkcji trygonometrycznych (sin, cos, ...), wykładniczej lub wielomianowej.

UPDATE: Zapraszamy do obejrzenia this page uzyskać więcej informacji na temat rozkładu prawdopodobieństwa

+1

WTF to wielomian? Metinks poszedł zbyt szybko przycisk "Opublikuj odpowiedź" – paxdiablo

+3

wielomian jest funkcją algebraiczną zapisaną w formie: f (x) = an x ​​x n + (an-1) * x^(x-1) + ... a2 * x^2 + a1 * x + a0; –

+0

Nie, to byłby * wielomian *. Widzę, że nikt tutaj nie docenia mojej (często dziwnej, zgodnie z tym, która musi być posłuszna) humoru. Myślę, że po prostu odejdę do łóżka. – paxdiablo

29

Musisz ważyć wyniki. Można zrobić coś takiego:

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

Gdybym wiedział, moja oferta była mała i spójne, będę korzystać z tabeli - to trywialne, aby jego własna klasa.

Dla kompletności dodam również tę klasę. Klasa ta pożycza od przetwarzania obrazu i używa funkcji korekcji gamma: wartość od 0 do 1 podniesiona do gamma, która zwraca wartość z zakresu od 0 do 1, ale jest dystrybuowana więcej do niższego końca, jeśli gamma < 1.0 i więcej do wyższego rzędu, jeśli 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; 
    } 
} 

(od komentarzy, przeniósł R z GetWeightedRandom(). Dodano także zakres kontroli do next())

OK, niech naprawdę iść do miasta tutaj. Przeznaczam na to Johna Skeeta - jest to klasa abstrakcyjna z właściwością szablonu, która zwraca funkcję przekształcenia, która odwzorowuje zakres [0..1] do [0..1] i skaluje liczbę losową do tego zakresu. Odwzorowałem również gamma pod kątem tego i zaimplementowałem grzech i cos.

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); } 
    } 
} 
+0

Ach, pokonałeś mnie tą odpowiedzią. +1. –

+3

Jest to dobre dla stosunkowo małych liczb, ale jeśli chcesz dystrybucji skoncentrowanej na 1000000, potrzebujesz naprawdę dużej tablicy ... Myślę, że lepiej byłoby użyć funkcji dystrybucji. –

+0

8 był przykładem, w rzeczywistości mamy: int głębokie zamiast 10, i nic zamiast 8 (to znaczy, że jest blisko 8 lub 7 lub 9) –

0

Wygląda na to, że chcesz, aby Twoje losowe liczby były ważone w kierunku najwyższej jakości - czy to byłaby rzetelna ocena?

Coś this może pomóc (to Java, ale stosuje się zasady)

+0

Nie, to niesprawiedliwe, ale ważne. –

2

Zamiast wariant tablicy, można również przyjrzeć się tej SO answer który ma link do Math.NET Iridium który implementuje niejednolitych losowe generatory .

Zaletą wariantu macierzy jest to, że uzyskuje się bardziej dynamiczne podejście, bez konieczności przepisywania tablicy przez cały czas. Można również zrobić rzeczy, które byłyby praktycznie niemożliwe przy wariancie macierzy (duże nierównomierne liczby losowe).

1

Przy pewnym obciążeniu, które powinno być możliwe. Zależy od tego, jak określisz "blisko osiem". Bardzo prosty sposób to zrobić:

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

Kwadrat będzie ważyć liczby w kierunku dolnego końca, tj.w tym przypadku 33% czasu otrzymasz 0, a otrzymasz 9 tylko około 5% czasu.

Ta metoda jest oczywiście dostosowana do konkretnego przypadku.

1

Nie dokładnie to, czego szukasz, ale bardzo prosty sposób na przybliżenie normalnego rozkładu liczb jest przez dodanie wielu pokoleń razem.

Klasycznym przykładem tej techniki jest gra Dungeons and Dragons, w której siłę postaci można określić, rzucając trzema sześciostronnymi kośćmi i dodając wyniki. Daje to zakres od 3 do 18, a liczba około 10 jest najbardziej prawdopodobna. Warianty to:

  • Toczenie 4 kostek i odrzucenie najniższego. To przekreśla rozkład w kierunku wyższych liczb.
  • Uśrednianie wyników zamiast ich dodawania. To sprawia, że ​​zakres wyjściowy jest łatwiejszy do zrozumienia.

Alternatywnie this jest całkiem blisko ...