Holen Sie sich eine Zufallszahl auf die Mitte konzentriert

238

Ist es möglich, eine Zufallszahl zwischen 1 und 100 zu erhalten und die Ergebnisse hauptsächlich im Bereich von 40 bis 60 zu halten? Ich meine, es wird selten außerhalb dieses Bereichs liegen, aber ich möchte, dass es hauptsächlich innerhalb dieses Bereichs liegt ... Ist es mit JavaScript / jQuery möglich?

Im Moment benutze ich nur das Basic Math.random() * 100 + 1.

Darryl Huffman
quelle
7
en.wikipedia.org/wiki/…
Roko C. Buljan
1
Mögliches Duplikat: stackoverflow.com/questions/1527803/…
Mahedi Sabuj
20
Mir gefällt, wohin diese Frage geht, aber ich denke, sie sollte spezifischer sein. Möchten Sie eine Z-Verteilung (Glockenkurve), eine Dreiecksverteilung oder eine Art Sägezahnverteilung? Meiner Meinung nach gibt es mehrere Möglichkeiten, diese Frage zu beantworten.
Patrick Roberts
12
Dies kann in Javascript erfolgen, hat aber sicher nichts mit jQuery zu tun ... :)
A. Wolff

Antworten:

397

Am einfachsten wäre es, zwei Zufallszahlen von 0 bis 50 zu generieren und zu addieren.

Dies ergibt eine Verteilung, die in Richtung 50 voreingenommen ist, auf die gleiche Weise, wie zwei Würfel in Richtung 7 gewürfelt werden.

In der Tat können Sie durch Verwendung einer größeren Anzahl von "Würfeln" (wie @Falco vorschlägt) eine Glockenkurve näher kommen:

function weightedRandom(max, numDice) {
    var num = 0;
    for (var i = 0; i < numDice; i++) {
        num += Math.random() * (max/numDice);
    }    
    return num;
}

Gewichtete Zufallszahlen

JSFiddle: http://jsfiddle.net/797qhcza/1/

BlueRaja - Danny Pflughoeft
quelle
12
Dies ist eine einfache und schnelle Lösung, die durch Hinzufügen weiterer Zahlen, z. B. 4 x (0-25), leichter gewichtet werden kann und eine schöne Glockenkurve für die Verteilung ergibt!
Falco
8
Dies ist ein fantastischer Code. Ich glaube, ich bin in sie verliebt. Einfach, schnell, effizient; gute Antwort. Vielen Dank für die Veröffentlichung.
ctwheels
14
Gute Antwort, aber falls jemand beabsichtigt, dies zur Erzeugung einer Normalverteilung zu verwenden, ist dies ziemlich ineffizient (und Sie müssen es transformieren, um den gewünschten Mittelwert und die gewünschte Standardabweichung zu erhalten). Eine effizientere Option wäre die Box-Muller-Transformation, die recht einfach zu implementieren und zu verstehen ist, wenn Sie sich mit Mathematik auskennen.
Brendon
1
@RaziShaban Es ist ziemlich intuitiv: Es gibt nur eine Kombination von Würfeln, die 2 ergibt (nur Schlangenaugen), aber es gibt 6 verschiedene Kombinationen, die 7 ergeben (6-1, 5-2, 4-3, 3-) 4, 2-5, 1-6). Wenn Sie auf N-seitige Würfel verallgemeinern, ist der Peak immer N + 1.
Barmar
2
@RaziShaban Die Untersuchung von Zufallsvariablen ist ein zentraler Bestandteil der Statistik. Die Tatsache, dass wir uns mit zunehmender Würfel einer Normalverteilung nähern, ist der berühmte zentrale Grenzwertsatz .
BlueRaja - Danny Pflughoeft
48

Sie haben hier einige gute Antworten, die spezifische Lösungen geben; Lassen Sie mich für Sie die allgemeine Lösung beschreiben. Das Problem ist:

  • Ich habe eine Quelle von mehr oder weniger gleichmäßig verteilten Zufallszahlen zwischen 0 und 1.
  • Ich möchte eine Folge von Zufallszahlen erzeugen, die einer anderen Verteilung folgen.

Die allgemeine Lösung für dieses Problem besteht darin, die Quantilfunktion Ihrer gewünschten Verteilung zu berechnen und dann die Quantilfunktion auf die Ausgabe Ihrer einheitlichen Quelle anzuwenden.

Die Quantilfunktion ist die Umkehrung des Integrals Ihrer gewünschten Verteilungsfunktion . Die Verteilungsfunktion ist die Funktion, bei der die Fläche unter einem Teil der Kurve gleich der Wahrscheinlichkeit ist, dass sich das zufällig ausgewählte Element in diesem Teil befindet.

Ich gebe hier ein Beispiel dafür:

http://ericlippert.com/2012/02/21/generating-random-non-uniform-data/

Der Code dort ist in C #, aber die Prinzipien gelten für jede Sprache. Es sollte einfach sein, die Lösung an JavaScript anzupassen.

Eric Lippert
quelle
2
Ich mag diesen Ansatz. Vielleicht möchten Sie hinzufügen, dass es eine Javascript-Bibliothek gibt, die Gaußsche (und andere nicht normale) Distributionen generiert
Floris
36

Das Aufnehmen von Zahlenfeldern usw. ist nicht effizient. Sie sollten eine Zuordnung vornehmen, die eine Zufallszahl zwischen 0 und 100 annimmt, und der gewünschten Verteilung zuordnen. In Ihrem Fall könnten Sie also eine Verteilung mit den meisten Werten in der Mitte Ihres Bereichs erhalten.f(x)=-(1/25)x2+4x

Verteilung

iCaramba
quelle
2
Wir wissen eigentlich nicht, welche Distribution benötigt wird. "Hauptsächlich 40-60" impliziert für mich eine Glockenkurve.
Lefty
Ja, Sie haben Recht, vielleicht brauchen Sie eine bessere Zuordnung, aber das ist trivial
iCaramba
3
Ich nehme Ihr Wort dafür, weil dies nicht mein Fachgebiet ist. Könnten Sie die Funktion anpassen und die neue Kurve anzeigen?
Lefty
1
@Lefty - Vereinfachte Glockenkurve für xzwischen 0 und 100 (aus dieser Frage entnommen ):y = (Math.sin(2 * Math.PI * (x/100 - 1/4)) + 1) / 2
Sphinxxx
@Sphinxxx Das ist keine Glockenkurve, es ist eine Sündenkurve. Eine Glockenkurve berührt niemals die x-Achse.
BlueRaja - Danny Pflughoeft
17

Ich könnte so etwas wie eine "Chance" einrichten, dass die Nummer "außerhalb der Grenzen" sein darf. In diesem Beispiel beträgt die Wahrscheinlichkeit 20%, dass die Zahl 1-100 beträgt, andernfalls 40-60:

$(function () {
    $('button').click(function () {
        var outOfBoundsChance = .2;
        var num = 0;
        if (Math.random() <= outOfBoundsChance) {
            num = getRandomInt(1, 100);
        } else {
            num = getRandomInt(40, 60);
        }
        $('#out').text(num);
    });
    
    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<button>Generate</button>
<div id="out"></div>

Geige: http://jsfiddle.net/kbv39s9w/

Bitweises Creative
quelle
5
Vielleicht kann mich jemand mit mehr statistischen Details korrigieren, und obwohl dies das erreicht, wonach das OP sucht (also habe ich abgestimmt), würde dies in 20% der Fälle nicht wirklich ein # außerhalb der Grenzen wählen, richtig? In dieser Lösung hätten Sie in 20% der Fälle die Möglichkeit, ein # von 1-100 auszuwählen, das 40-60 enthält. Wäre dies nicht tatsächlich (0,2 * 0,8) 16%, um ein # außerhalb der Grenzen zu wählen, oder fehlt mir etwas?
Josh
Nein, du hast recht. Es ist nur meine Formulierung. Ich werde es korrigieren. Danke dir!
Bitwise Creative
1
@ Josh - Das ist ziemlich genau richtig. Hier ist ein einfacher Beweis dafür, wie das aussieht: jsfiddle.net/v51z8sd5 . Es wird der Prozentsatz der Zahlen angezeigt, die außerhalb der Grenzen gefunden wurden und bei 0,16 (16%) liegen.
Travis J
15

Ich musste dieses Problem vor einigen Jahren lösen und meine Lösung war einfacher als jede andere Antwort.

Ich habe 3 Zufälle zwischen den Grenzen generiert und sie gemittelt. Dies zieht das Ergebnis in Richtung Zentrum, lässt es jedoch vollständig möglich, die Extremitäten zu erreichen.

Lefty
quelle
7
Wie ist das besser / anders als die Antwort von BlueRaja? Dort nimmt er die Summe von (2,3, ... jede beliebige Zahl) Zufallszahlen und nimmt den Durchschnitt. Das Ergebnis ist identisch mit Ihrem, wenn Sie eine BellFactorvon 3 verwenden.
Floris
@floris Nun, ich codiere nicht in der c-Sprachfamilie, so dass die Antwort nicht einmal so aussah, als würde sie das Gleiche tun wie meine Antwort, bis ich sie jetzt noch einmal gelesen habe. Ich habe meine Methode durch ein wenig Versuch und Irrtum erstellt und festgestellt, dass 3 Zufälle die richtige Zahl sind. Außerdem kann meine in einer Zeile ausgeführt werden und ist dennoch leicht zu verstehen.
Lefty
2
"Ja wirklich?" Sie glauben nicht, dass es eine Ähnlichkeit zwischen JS und C gibt? OK, sagen wir einfach, ich kann weder diese Sprachen noch Java sprechen, die mir im Vergleich zu den mir bekannten Sprachen alle ähnlich sind.
Lefty
1
Fairerweise war ich nur vom Titel als etwas angezogen, das ich selbst gelöst hatte, und war ziemlich stolz auf die Art und Weise, wie ich es tat. Wieder war mir nicht bewusst, dass es eine js-Frage ist, bis Sie das gerade gesagt haben. Wirklich glücklich, denn meine Technik ist nicht sprachabhängig und einige Leute scheinen zu denken, dass es eine nützliche Antwort ist.
Lefty
5
JavaScript tatsächlich ist eine C-Familie Sprache ... aber ah gut.
Joren
14

Es sieht dumm aus, aber Sie können Rand zweimal verwenden:

var choice = Math.random() * 3;
var result;

if (choice < 2){
    result = Math.random() * 20 + 40; //you have 2/3 chance to go there
}
else {
    result = Math.random() * 100 + 1;
}
max890
quelle
11

Sicher ist es möglich. Machen Sie eine zufällige 1-100. Wenn die Zahl <30 ist, generieren Sie eine Zahl im Bereich von 1 bis 100, wenn nicht im Bereich von 40 bis 60.

Luka Krajnc
quelle
11

Es gibt viele verschiedene Möglichkeiten, solche Zufallszahlen zu generieren. Eine Möglichkeit besteht darin, die Summe mehrerer einheitlicher Zufallszahlen zu berechnen. Wie viele Zufallszahlen Sie summieren und wie hoch ihr Bereich ist, bestimmt, wie die endgültige Verteilung aussehen wird.

Je mehr Zahlen Sie zusammenfassen, desto stärker ist die Tendenz zur Mitte hin. Die Verwendung der Summe von 1 Zufallszahl wurde bereits in Ihrer Frage vorgeschlagen, ist jedoch, wie Sie bemerken, nicht auf die Mitte des Bereichs ausgerichtet. Andere Antworten haben vorgeschlagen, die Summe von 2 Zufallszahlen oder die Summe von 3 Zufallszahlen zu verwenden .

Sie können noch mehr Vorurteile in Richtung der Mitte des Bereichs erzielen, indem Sie die Summe von mehr Zufallszahlen nehmen. Im Extremfall könnte man die Summe von 99 Zufallszahlen nehmen, die jeweils entweder 0 oder 1 sind. Das wäre eine Binomialverteilung. (Binomialverteilungen können in gewissem Sinne als diskrete Version von Normalverteilungen angesehen werden). Dies kann theoretisch immer noch den gesamten Bereich abdecken, ist jedoch so stark auf das Zentrum ausgerichtet, dass Sie niemals erwarten sollten, dass es die Endpunkte erreicht.

Dieser Ansatz bedeutet, dass Sie genau festlegen können, wie viel Voreingenommenheit Sie möchten.

Kasperd
quelle
8

Was ist mit so etwas:

var loops = 10;
var tries = 10;
var div = $("#results").html(random());
function random() {
    var values = "";
    for(var i=0; i < loops; i++) {
        var numTries = tries;
        do {
            var num = Math.floor((Math.random() * 100) + 1);
            numTries--;
        }
        while((num < 40 || num >60) && numTries > 1)
        values += num + "<br/>";
    }
    return values;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="results"></div>

So wie ich es codiert haben können Sie ein paar Variablen setzen:
Schleifen = Anzahl der Ergebnisse
versucht = Anzahl , wie oft die Funktion versucht , eine Zahl zwischen 40-60 zu erhalten , bevor es stoppt durch die while - Schleife laufen

Zusätzlicher Bonus: Es verwendet do while !!! Großartigkeit von seiner besten Seite

ctwheels
quelle
8

Sie können eine Funktion schreiben , die Zufallswerte abbildet zwischen [0, 1)bis [1, 100]nach Gewicht. Betrachten Sie dieses Beispiel:

0,0-1,0 bis 1-100 nach Gewichtsprozent

Hier wird der Wert 0.95dem Wert zwischen zugeordnet [61, 100].
In der Tat haben wir .05 / .1 = 0.5, was, wenn abgebildet [61, 100], ergibt81 .

Hier ist die Funktion:

/*
 * Function that returns a function that maps random number to value according to map of probability
 */
function createDistributionFunction(data) {
  // cache data + some pre-calculations
  var cache = [];
  var i;
  for (i = 0; i < data.length; i++) {
    cache[i] = {};
    cache[i].valueMin = data[i].values[0];
    cache[i].valueMax = data[i].values[1];
    cache[i].rangeMin = i === 0 ? 0 : cache[i - 1].rangeMax;
    cache[i].rangeMax = cache[i].rangeMin + data[i].weight;
  }
  return function(random) {
    var value;
    for (i = 0; i < cache.length; i++) {
      // this maps random number to the bracket and the value inside that bracket
      if (cache[i].rangeMin <= random && random < cache[i].rangeMax) {
        value = (random - cache[i].rangeMin) / (cache[i].rangeMax - cache[i].rangeMin);
        value *= cache[i].valueMax - cache[i].valueMin + 1;
        value += cache[i].valueMin;
        return Math.floor(value);
      }
    }
  };
}

/*
 * Example usage
 */
var distributionFunction = createDistributionFunction([
  { weight: 0.1, values: [1, 40] },
  { weight: 0.8, values: [41, 60] },
  { weight: 0.1, values: [61, 100] }
]);

/*
 * Test the example and draw results using Google charts API
 */
function testAndDrawResult() {
  var counts = [];
  var i;
  var value;
  // run the function in a loop and count the number of occurrences of each value
  for (i = 0; i < 10000; i++) {
    value = distributionFunction(Math.random());
    counts[value] = (counts[value] || 0) + 1;
  }
  // convert results to datatable and display
  var data = new google.visualization.DataTable();
  data.addColumn("number", "Value");
  data.addColumn("number", "Count");
  for (value = 0; value < counts.length; value++) {
    if (counts[value] !== undefined) {
      data.addRow([value, counts[value]]);
    }
  }
  var chart = new google.visualization.ColumnChart(document.getElementById("chart"));
  chart.draw(data);
}
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(testAndDrawResult);
<script src="https://www.google.com/jsapi"></script>
<div id="chart"></div>

Salman A.
quelle
7

Hier ist eine gewichtete Lösung bei 3/4 40-60 und 1/4 außerhalb dieses Bereichs.

function weighted() {

  var w = 4;

  // number 1 to w
  var r = Math.floor(Math.random() * w) + 1;

  if (r === 1) { // 1/w goes to outside 40-60
    var n = Math.floor(Math.random() * 80) + 1;
    if (n >= 40 && n <= 60) n += 40;
    return n
  }
  // w-1/w goes to 40-60 range.
  return Math.floor(Math.random() * 21) + 40;
}

function test() {
  var counts = [];

  for (var i = 0; i < 2000; i++) {
    var n = weighted();
    if (!counts[n]) counts[n] = 0;
    counts[n] ++;
  }
  var output = document.getElementById('output');
  var o = "";
  for (var i = 1; i <= 100; i++) {
    o += i + " - " + (counts[i] | 0) + "\n";
  }
  output.innerHTML = o;
}

test();
<pre id="output"></pre>

Wolfshammer
quelle
6

Ok, also habe ich beschlossen, eine weitere Antwort hinzuzufügen, da ich der Meinung war, dass meine letzte Antwort sowie die meisten Antworten hier eine halbstatistische Methode verwenden, um eine Ergebnisrendite vom Typ Glockenkurve zu erhalten. Der Code, den ich unten gebe, funktioniert genauso wie beim Würfeln. Daher ist es am schwierigsten, 1 oder 99 zu bekommen, aber am einfachsten, 50 zu bekommen.

var loops = 10; //Number of numbers generated
var min = 1,
    max = 50;
var div = $("#results").html(random());

function random() {
    var values = "";
    for (var i = 0; i < loops; i++) {
        var one = generate();
        var two = generate();
        var ans = one + two - 1;
        var num = values += ans + "<br/>";
    }
    return values;
}

function generate() {
    return Math.floor((Math.random() * (max - min + 1)) + min);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="results"></div>

ctwheels
quelle
6

Ich würde empfehlen, die Beta-Distribution zu verwenden zu verwenden, um eine Zahl zwischen 0 und 1 zu generieren und sie dann zu vergrößern. Es ist sehr flexibel und kann viele verschiedene Formen von Verteilungen erstellen.

Hier ist ein schneller und schmutziger Sampler:

rbeta = function(alpha, beta) {
 var a = 0   
 for(var i = 0; i < alpha; i++)   
    a -= Math.log(Math.random())

 var b = 0   
 for(var i = 0; i < beta; i++)   
    b -= Math.log(Math.random())

  return Math.ceil(100 * a / (a+b))
}
Neal Fultz
quelle
5
var randNum;
// generate random number from 1-5
var freq = Math.floor(Math.random() * (6 - 1) + 1);
// focus on 40-60 if the number is odd (1,3, or 5)
// this should happen %60 of the time
if (freq % 2){
    randNum = Math.floor(Math.random() * (60 - 40) + 40);
}
else {
    randNum = Math.floor(Math.random() * (100 - 1) + 1);
}
Olaide Oyekoya
quelle
5

Die beste Lösung für dieses Problem ist die von BlueRaja - Danny Pflughoeft vorgeschlagene, aber ich denke, eine etwas schnellere und allgemeinere Lösung ist ebenfalls erwähnenswert.


Wenn ich Zufallszahlen (Zeichenfolgen, Koordinatenpaare usw.) generieren muss, die die beiden Anforderungen von erfüllen

  1. Die Ergebnismenge ist ziemlich klein. (nicht größer als 16K Zahlen)
  2. Die Ergebnismenge ist diskret. (wie nur ganzzahlige Zahlen)

Normalerweise beginne ich damit, ein Array von Zahlen (Zeichenfolgen, Koordinatenpaare usw.) zu erstellen, das die Anforderung erfüllt (in Ihrem Fall: ein Array von Zahlen, die die wahrscheinlicheren mehrmals enthalten.), Und wähle dann ein zufälliges Element dieses Arrays aus. Auf diese Weise müssen Sie die teure Zufallsfunktion nur einmal pro Artikel aufrufen.

mg30rg
quelle
1
Wenn Sie eine Reihe von Auswahlmöglichkeiten vorab ausfüllen möchten, können Sie diese auch nachträglich mischen. Dann können Sie sie einfach der Reihe nach greifen, bis Sie ausgehen. Mische erneut, wenn du das Ende der Liste erreicht hast.
Geobits
@Geobits Das Mischen einer Liste ist eine weitaus ressourcenintensivere Aufgabe als die zufällige Auswahl eines ihrer Elemente. Es ist nur dann eine gute Wahl, wenn die Liste vorhersehbar sein muss.
mg30rg
1
Sie tun dies jedoch nur einmal pro Zyklus der Liste und nicht jedes Mal. Wenn Sie dies vorverarbeiten (da Sie sowieso einen Vorverarbeitungsschritt haben, gehe ich davon aus, dass dies in Ordnung ist), ist es sehr schnell, jede Nummer danach abzurufen. Sie können jederzeit neu mischen, wenn Sie Ausfallzeiten haben oder wissen, dass Sie für eine Weile keine Zufallszahl benötigen. Nur als Alternative anzubieten, haben beide (Nachteile).
Geobits
@Geobits Wenn Sie es auf Ihre Weise tun, fallen die "Single Probability" -Zahlen "heraus" und können bis zum erneuten Mischen nicht angezeigt werden. (dh wenn Sie das Werfen von zwei Würfeln simulieren, haben Sie nicht die geringste Chance, Nummer 2 mehr als zweimal zu bekommen.)
mg30rg
1
Das ist ein viel besserer Grund, es nicht zu benutzen, außer für die seltenen Anwendungen, bei denen das in Ordnung ist;)
Geobits
4

Verteilung

 5% for [ 0,39]
90% for [40,59]
 5% for [60,99]

Lösung

var f = Math.random();
if (f < 0.05) return random(0,39);
else if (f < 0.95) return random(40,59);
else return random(60,99);

Generische Lösung

random_choose([series(0,39),series(40,59),series(60,99)],[0.05,0.90,0.05]);

function random_choose (collections,probabilities)
{
    var acc = 0.00;
    var r1 = Math.random();
    var r2 = Math.random();

    for (var i = 0; i < probabilities.length; i++)
    {
      acc += probabilities[i];
      if (r1 < acc)
        return collections[i][Math.floor(r2*collections[i].length)];
    }

    return (-1);
}

function series(min,max)
{
    var i = min; var s = [];
    while (s[s.length-1] < max) s[s.length]=i++;
    return s;
}
Khaled.K
quelle
4

Sie können eine Hilfs-Zufallszahl verwenden, um Zufallszahlen in 40-60 oder 1-100 zu generieren:

// 90% of random numbers should be between 40 to 60.
var weight_percentage = 90;

var focuse_on_center = ( (Math.random() * 100) < weight_percentage );

if(focuse_on_center)
{
	// generate a random number within the 40-60 range.
	alert (40 + Math.random() * 20 + 1);
}
else
{
	// generate a random number within the 1-100 range.
	alert (Math.random() * 100 + 1);
}

Amir Saniyan
quelle
4

Wenn Sie die gaussianFunktion verwenden können, verwenden Sie sie. Diese Funktion gibt die normale Nummer mit average 0und zurück sigma 1.

95% dieser Zahl sind innerhalb average +/- 2*sigma. Dein average = 50und sigma = 5so

randomNumber = 50 + 5*gaussian()
Павел Бивойно
quelle
3

Der beste Weg, dies zu tun, besteht darin, eine Zufallszahl zu generieren, die gleichmäßig in einem bestimmten Satz von Zahlen verteilt ist, und dann eine Projektionsfunktion auf den Satz zwischen 0 und 100 anzuwenden, bei der die Projektion mit größerer Wahrscheinlichkeit die gewünschten Zahlen trifft.

Normalerweise besteht der mathematische Weg, dies zu erreichen, darin, eine Wahrscheinlichkeitsfunktion der gewünschten Zahlen zu zeichnen. Wir könnten die Glockenkurve verwenden, aber zur einfacheren Berechnung arbeiten wir einfach mit einer umgedrehten Parabel.

Lassen Sie uns eine Parabel so machen, dass ihre Wurzeln bei 0 und 100 liegen, ohne sie zu verzerren. Wir erhalten die folgende Gleichung:

f(x) = -(x-0)(x-100) = -x * (x-100) = -x^2 + 100x

Jetzt ist der gesamte Bereich unter der Kurve zwischen 0 und 100 repräsentativ für unseren ersten Satz, in dem die Zahlen generiert werden sollen. Dort ist die Generation völlig zufällig. Wir müssen also nur die Grenzen unseres ersten Satzes finden.

Die Untergrenze ist natürlich 0. Die Obergrenze ist das Integral unserer Funktion bei 100

F(x) = -x^3/3 + 50x^2
F(100) = 500,000/3 = 166,666.66666 (let's just use 166,666, because rounding up would make the target out of bounds)

Wir wissen also, dass wir irgendwo zwischen 0 und 166.666 eine Zahl generieren müssen. Dann müssen wir einfach diese Zahl nehmen und auf unseren zweiten Satz projizieren, der zwischen 0 und 100 liegt.

Wir wissen, dass die Zufallszahl, die wir generiert haben, ein Integral unserer Parabel mit einer Eingabe x zwischen 0 und 100 ist. Das bedeutet, dass wir einfach annehmen müssen, dass die Zufallszahl das Ergebnis von F (x) ist, und nach x auflösen müssen.

In diesem Fall ist F (x) eine kubische Gleichung, und in der Form F(x) = ax^3 + bx^2 + cx + d = 0sind die folgenden Aussagen wahr:

a = -1/3
b = 50
c = 0
d = -1 * (your random number)

Wenn Sie dies nach x lösen, erhalten Sie die tatsächliche Zufallszahl, nach der Sie suchen. Diese liegt garantiert im Bereich [0, 100] und hat eine viel höhere Wahrscheinlichkeit, nahe am Zentrum als an den Kanten zu liegen.

arik
quelle
3

Diese Antwort ist wirklich gut . Aber ich möchte Implementierungsanweisungen (ich bin nicht in JavaScript, also hoffe ich, dass Sie verstehen) für eine andere Situation veröffentlichen.


Angenommen, Sie haben Bereiche und Gewichte für jeden Bereich:

ranges - [1, 20], [21, 40], [41, 60], [61, 100]
weights - {1, 2, 100, 5}

Anfängliche statische Informationen können zwischengespeichert werden:

  1. Summe aller Gewichte (108 in Probe)
  2. Bereichsauswahlgrenzen. Es ist im Grunde diese Formel: Boundary[n] = Boundary[n - 1] + weigh[n - 1]und Boundary[0] = 0. Probe hatBoundary = {0, 1, 3, 103, 108}

Zahlengenerierung:

  1. Generieren Sie eine Zufallszahl Naus dem Bereich [0, Summe aller Gewichte].
  2. for (i = 0; i < size(Boundary) && N > Boundary[i + 1]; ++i)
  3. Nehmen Sie den iBereich und generieren Sie eine Zufallszahl in diesem Bereich.

Zusätzlicher Hinweis für Leistungsoptimierungen. Bereiche müssen weder in aufsteigender noch in absteigender Reihenfolge geordnet werden. Für eine schnellere Reichweite sollte der Suchbereich mit dem höchsten Gewicht an erster Stelle und einer mit dem niedrigsten Gewicht an letzter Stelle stehen.

ST3
quelle