Bestimmung eines (Zufalls)Ereignis

Luk10

Top Contributor
Grüße,

Ich suche nach einem einfachen und effizienten Weg Zufallsereignisse zu bestimmen.

Beispiel:

Methode gibt mir einen boolean Wert: 37% der Aufrufe soll false zurückgegeben werden 63% der Aufrufe true.

Einfacher Ansatz:

Java:
public boolean randomEvent() {
  boolean random = true;
  int newRandom = (int) (Math.random() * 100)

  if(newRandom < 37) {
    random = false;
  }
  return random;
}

Sollte mit einer Wahrscheinlichkeit von 37% false zurückgeben.

Leider ist mein konkretes Problem komplexer. Ich möchte einen
Code:
int random
Wert zurückgegeben haben, der
> mit einer Wahrscheinlichkeit von 7,34% 0 ist
> mit einer Wahrscheinlichkeit von 3,445% 1 ist
> mit einer Wahrscheinlichkeit von 54,7% 2 ist
> ...

Diese Liste geht bis ca
Code:
random = 20
. Das mit
Code:
if / else
bzw
Code:
switch
zu machen ist ziemlich langwierig und aufwendig ...

Gibt es eine einfachere Möglichkeit so ein Problem zu lösen?

Danke,
-Luk10-
 
Ungetestet...

Java:
private static double[] prob = {7.34, 3.445, 54.7}; 

public boolean randomEvent() {
  double r = Math.random() * 100;
 
  double ps = 0;
  for(int i = 0; i < prob.length; i++) { 
    ps += prob[i];
    if (r <= ps) return i;
  }
  return prob.length;
}
 
Getestet, aber war nur ein spontaner Gedanke - theoretisch bei vielen Zufallswerten schneller, aber praktisch (durch Autoboxing) vermutlich deutlich langsamer.
Java:
import java.util.*;
import java.util.Map.*;


public class RandomDistributionTest
{
    public static void main(String args[])
    {
        double probabilities[] = new double[] {
            0.0734, 0.03445, 0.547, 0.34515
        };

        RandomDistribution r = new RandomDistribution(probabilities);

        int n = 100000;
        int counters[] = new int[probabilities.length];
        for (int i=0; i<n; i++)
        {
            int index = r.getRandomInt();
            counters[index]++;
        }

        for (int i=0; i<probabilities.length; i++)
        {
            System.out.println("For "+i+" got "+(double)counters[i]/n+" expected "+probabilities[i]);
        }

    }
}


class RandomDistribution
{
    private final Random random;
    private final TreeMap<Double, Integer> map;

    public RandomDistribution(double ... probabilities)
    {
        random = new Random(0);
        map = new TreeMap<Double, Integer>();
        double sum = 0;
        for (int i=0; i<probabilities.length; i++)
        {
            map.put(sum, i);
            sum += probabilities[i];
        }
    }

    public int getRandomInt()
    {
        double value = random.nextDouble();
        Entry<Double, Integer> entry = map.floorEntry(value);
        //System.out.println("For "+value+" entry "+entry+" in "+map);
        return entry.getValue();
    }

}


Bin nur gerade ein Fan von NavigableMap 😳
 
Wenn es wirklich auf Geschwindigkeit ankommt, kann man das Array mit bereits kumulierten Wahrscheinlichkeiten ablegen, und die richtige "Schublade" mit [c]Arrays.binarySearch()[/c] finden.
 
Der Einfachheit halber verwende ich Landei's Ansatz. Leider hab ich ein Problem, das ich im Moment irgendwie einfach nicht gelöst bekomme:

Ich will eine Verteilung von

Code:
dis: 50% - 25% - 25%
Code:
int:  0    -   1    -  2

Also zwei Ereignisse sollen gleichwahrscheinlich sein. Ich vermute, dass der Ansatz so wie er ist nichtmehr funktioniert ... wie kann ich ihn so verändern, dass auch gleich wahrscheinliche Ereignisse korrekt in einen int - Wert umgesetzt werden?

Danke,
-Luk10-
 
wenn du diesen Ansatz meinst, der sollte auch bei (50, 25, 25) funktionieren. Da passiert ja folgendes

- <= 50% --> 0 (0 - 50)
- <= 75% --> 1 (51 - 75)
- <=100% --> 2 (76 - 100)


Ungetestet...

Java:
private static double[] prob = {7.34, 3.445, 54.7}; 

public boolean randomEvent() {
  double r = Math.random() * 100;
 
  double ps = 0;
  for(int i = 0; i < prob.length; i++) { 
    ps += prob[i];
    if (r <= ps) return i;
  }
  return prob.length;
}
 
Funzt genauso... (Wahrscheinlichkeiten gebe ich eher zwischen 0 und 1 als zwischen 0 und 100 an - aber das ist nur ein Detail)
Java:
import java.util.*;
import java.util.Map.*;


public class RandomDistributionTest2
{
    public static void main(String args[])
    {
        double probabilities[] = new double[] {
            0.0734, 0.03445, 0.547, 0.34515
        };


        int n = 100000;
        int counters[] = new int[probabilities.length];
        for (int i=0; i<n; i++)
        {
            int index = randomEvent(probabilities);
            counters[index]++;
        }

        for (int i=0; i<probabilities.length; i++)
        {
            System.out.println("For "+i+" got "+(double)counters[i]/n+" expected "+probabilities[i]);
        }

    }

    public static int randomEvent(double[] prob) {
      double r = Math.random();

      double ps = 0;
      for(int i = 0; i < prob.length; i++) {
        ps += prob[i];
        if (r <= ps) {
            return i;
        }
      }
      return prob.length;
    }
}
 

Neue Themen


Zurück
Oben