Dapatkan nomor acak yang fokus di tengah

238

Apakah mungkin untuk mendapatkan angka acak antara 1-100 dan mempertahankan hasil utamanya dalam kisaran 40-60? Maksud saya, itu akan keluar dari kisaran itu jarang, tetapi saya ingin itu terutama dalam kisaran itu ... Apakah mungkin dengan JavaScript / jQuery?

Saat ini saya hanya menggunakan dasar Math.random() * 100 + 1.

Darryl Huffman
sumber
7
en.wikipedia.org/wiki/…
Roko C. Buljan
1
kemungkinan rangkap: stackoverflow.com/questions/1527803/…
Mahedi Sabuj
20
Saya suka ke mana pertanyaan ini pergi, tetapi saya pikir itu harus lebih spesifik. Apakah Anda menginginkan distribusi Z (kurva lonceng), distribusi segitiga, atau semacam distribusi gigi gergaji? Ada beberapa kemungkinan untuk menjawab pertanyaan ini menurut saya.
Patrick Roberts
12
Ini dapat dilakukan dalam javascript tetapi pastinya tidak ada hubungannya dengan jQuery ... :)
A. Wolff

Jawaban:

397

Cara paling sederhana adalah dengan menghasilkan dua angka acak dari 0-50 dan menambahkannya bersama.

Ini memberikan distribusi yang bias terhadap 50, dengan cara yang sama menggulirkan dua bias dadu menuju 7.

Bahkan, dengan menggunakan jumlah "dadu" yang lebih besar (seperti yang disarankan @Falco) , Anda dapat membuat perkiraan yang lebih dekat dengan kurva lonceng:

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

Nomor acak tertimbang

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

BlueRaja - Danny Pflughoeft
sumber
12
Ini adalah solusi yang mudah dan cepat, yang dapat dengan mudah ditimbang lebih banyak, dengan menambahkan lebih banyak angka misalnya 4 x (0-25) dan akan memberi Anda kurva lonceng yang bagus untuk distribusi!
Falco
8
Ini adalah kode yang fantastis. Saya pikir saya cinta dengannya. Sederhana, cepat, efisien; jawaban yang bagus Terima kasih telah memposting ini.
ctwheels
14
Jawaban yang bagus, tetapi kalau-kalau ada orang yang ingin menggunakan ini untuk menghasilkan distribusi Normal, itu cukup tidak efisien (dan Anda perlu mengubahnya untuk mendapatkan mean dan standar deviasi yang diinginkan). Opsi yang lebih efisien adalah transformasi Box-Muller, yang cukup mudah diterapkan dan dipahami jika Anda tahu sedikit matematika.
Brendon
1
@RaziShaban Ini cukup intuitif: Hanya ada satu kombinasi lemparan mati yang menambahkan hingga 2 (hanya mata ular), tetapi ada 6 kombinasi berbeda yang menambahkan hingga 7 (6-1, 5-2, 4-3, 3- 4, 2-5, 1-6). Jika Anda menggeneralisasi ke dadu sisi-N, puncaknya selalu N + 1.
Barmar
2
@RaziShaban Studi tentang variabel acak adalah bagian utama dari statistik. Fakta bahwa ketika kita meningkatkan dadu kita mendekati distribusi normal adalah Central Limit Theorem yang terkenal .
BlueRaja - Danny Pflughoeft
48

Anda memiliki beberapa jawaban yang baik di sini yang memberikan solusi spesifik; izinkan saya menjelaskan untuk Anda solusi umum. Masalahnya adalah:

  • Saya memiliki sumber bilangan acak yang terdistribusi kurang lebih seragam antara 0 dan 1.
  • Saya ingin menghasilkan urutan angka acak yang mengikuti distribusi yang berbeda.

Solusi umum untuk masalah ini adalah mengerjakan fungsi kuantil dari distribusi yang Anda inginkan, dan kemudian menerapkan fungsi kuantil ke output sumber seragam Anda.

Fungsi kuantil adalah kebalikan dari integral fungsi distribusi yang Anda inginkan . Fungsi distribusi adalah fungsi di mana area di bawah bagian kurva sama dengan probabilitas bahwa item yang dipilih secara acak akan berada di bagian itu.

Saya memberikan contoh bagaimana melakukannya di sini:

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

Kode di sana ada di C #, tetapi prinsipnya berlaku untuk bahasa apa pun; harus mudah untuk menyesuaikan solusi untuk JavaScript.

Eric Lippert
sumber
2
Saya suka pendekatan ini. Mungkin ingin menambahkan bahwa ada perpustakaan javascript yang menghasilkan distribusi Gaussian (dan non-normal lainnya): simjs.com/random.html
Floris
36

Mengambil array angka, dll. Tidak efisien. Anda harus mengambil pemetaan yang mengambil angka acak antara 0 hingga 100 dan memetakan distribusi yang Anda butuhkan. Jadi dalam kasus Anda, Anda bisa mengambil untuk mendapatkan distribusi dengan nilai terbanyak di tengah rentang Anda.f(x)=-(1/25)x2+4x

Distribusi

iCaramba
sumber
2
Kami sebenarnya tidak tahu distribusi apa yang dibutuhkan. "Terutama 40-60" menyiratkan lonceng bagiku.
Lefty
ya Anda benar, mungkin Anda perlu pemetaan yang lebih baik, tapi itu sepele
iCaramba
3
Saya akan mengambil kata-kata Anda untuk itu karena ini bukan bidang keahlian saya. Bisakah Anda menyesuaikan fungsi dan menampilkan kurva baru?
Lefty
1
@Lefty - Kurva bel sederhana untuk xantara 0 dan 100 (diambil dari pertanyaan ini ):y = (Math.sin(2 * Math.PI * (x/100 - 1/4)) + 1) / 2
Sphinxxx
@Sphinxxx Itu bukan kurva lonceng, itu kurva dosa. Kurva lonceng tidak pernah menyentuh sumbu x.
BlueRaja - Danny Pflughoeft
17

Saya mungkin melakukan sesuatu seperti mengatur "peluang" agar nomor diizinkan keluar "di luar batas". Dalam contoh ini, peluang 20% ​​jumlahnya akan menjadi 1-100, jika tidak, 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>

fiddle: http://jsfiddle.net/kbv39s9w/

Kreatif bitwise
sumber
5
Mungkin seseorang dengan lebih banyak detail statistik dapat mengoreksi saya, dan meskipun ini mencapai apa yang dicari OP (jadi saya memilih), tetapi ini tidak akan benar-benar memilih # di luar batas 20% dari waktu, benar? Dalam solusi ini, 20% dari waktu Anda memiliki kesempatan untuk kemudian memilih # dari 1-100, yang mencakup 40-60. Bukankah ini sebenarnya (0,2 * 0,8) 16% untuk memilih # di luar batas, atau apakah saya kehilangan sesuatu?
Josh
Tidak, kamu benar. Itu hanya kata-kata saya. Saya akan memperbaikinya. Terima kasih!
Bitwise Creative
1
@ Ya ampun - Itu cukup tepat. Berikut ini adalah bukti sederhana dari apa yang terlihat seperti jsfiddle.net/v51z8sd5 . Ini akan menunjukkan persentase angka yang ditemukan di luar batas dan berkisar sekitar 0,16 (16%).
Travis J
15

Saya perlu memecahkan masalah ini beberapa tahun yang lalu dan solusi saya lebih mudah daripada jawaban lainnya.

Saya menghasilkan 3 tebusan antara batas dan rata-rata. Ini menarik hasilnya ke arah tengah, tetapi memungkinkan sepenuhnya mencapai ekstremitas.

Orang kidal
sumber
7
Bagaimana ini lebih baik / berbeda dari jawaban BlueRaja? Di sana, ia mengambil jumlah (2,3, ... nomor apa pun yang Anda inginkan) angka acak dan mengambil rata-rata. Hasilnya identik dengan Anda ketika Anda menggunakan a BellFactordari 3.
Floris
@floris yah, saya tidak kode dalam kelompok bahasa sehingga jawaban itu bahkan tidak terlihat seolah-olah melakukan hal yang sama dengan jawaban saya sampai saya membaca ulang sekarang. Saya menciptakan metode saya dengan sedikit trial-and-error dan menemukan bahwa 3 tebusan adalah angka yang tepat. Juga, milikku dapat dilakukan dalam satu baris dan masih mudah dimengerti.
kidal
2
Betulkah? Anda tidak berpikir ada kesamaan antara JS dan C? Oke, yah, anggap saja saya tidak bisa berbicara BAIK dari bahasa-bahasa itu, juga Jawa, yang bagi saya, semuanya serupa dibandingkan dengan bahasa-bahasa yang saya kenal.
kidal
1
Poin yang adil, saya sebenarnya tertarik hanya oleh judul sebagai sesuatu yang telah saya pecahkan sendiri dan cukup bangga dengan cara saya melakukannya. Sekali lagi, saya tidak menyadari itu adalah pertanyaan js sampai Anda baru saja mengatakan itu. Beruntung banget, karena teknik saya tidak tergantung pada bahasa dan beberapa orang tampaknya menganggap itu jawaban yang berguna.
kidal
5
JavaScript sebenarnya adalah bahasa C-family ... tapi ah well.
Joren
14

Ini terlihat bodoh tetapi Anda dapat menggunakan rand dua kali:

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;
}
maks890
sumber
11

Tentu itu mungkin. Buat 1-100 acak. Jika angkanya <30 maka hasilkan angka dalam kisaran 1-100 jika tidak menghasilkan dalam kisaran 40-60.

Luka Krajnc
sumber
11

Ada banyak cara berbeda untuk menghasilkan angka acak tersebut. Salah satu cara untuk melakukannya adalah dengan menghitung jumlah dari beberapa angka acak yang seragam. Berapa banyak angka acak yang Anda jumlah dan berapa kisarannya akan menentukan bagaimana distribusi akhir akan terlihat.

Semakin banyak angka yang Anda simpulkan, semakin bias ke arah pusat. Menggunakan jumlah 1 angka acak sudah diusulkan dalam pertanyaan Anda, tetapi karena Anda perhatikan tidak bias menuju pusat kisaran. Jawaban lain mengusulkan menggunakan jumlah 2 angka acak atau jumlah 3 angka acak .

Anda bahkan bisa mendapatkan lebih banyak bias ke tengah rentang dengan mengambil jumlah angka yang lebih acak. Pada ekstrem Anda bisa mengambil jumlah 99 angka acak yang masing-masing 0 atau 1. Itu akan menjadi distribusi binomial. (Distribusi binomial dalam beberapa hal dapat dilihat sebagai versi diskrit dari distribusi normal). Secara teori ini masih dapat mencakup keseluruhan, tetapi memiliki begitu banyak bias ke pusat sehingga Anda tidak boleh berharap untuk melihatnya mencapai titik akhir.

Pendekatan ini berarti Anda dapat mengubah seberapa besar bias yang Anda inginkan.

kasperd
sumber
8

Bagaimana dengan menggunakan sesuatu seperti ini:

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>

Cara saya mengkodekannya memungkinkan Anda untuk mengatur beberapa variabel:
loop = jumlah hasil
mencoba = berapa kali fungsi akan mencoba untuk mendapatkan angka antara 40-60 sebelum berhenti berjalan melalui loop sementara

Bonus tambahan: Ini digunakan do !!! Keagungan yang terbaik

lihat roda
sumber
8

Anda dapat menulis fungsi yang memetakan nilai-nilai acak antara [0, 1)untuk [1, 100]sesuai dengan berat badan. Pertimbangkan contoh ini:

0,0-1,0 hingga 1-100 berdasarkan persentase berat

Di sini, nilai 0.95memetakan ke nilai antara [61, 100].
Sebenarnya kita memiliki .05 / .1 = 0.5, yang, ketika dipetakan [61, 100], menghasilkan 81.

Inilah fungsinya:

/*
 * 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
sumber
7

Inilah solusi berbobot pada 3/4 40-60 dan 1/4 di luar rentang itu.

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>

wolfhammer
sumber
6

Ok, jadi saya memutuskan untuk menambahkan jawaban lain karena saya merasa seperti jawaban terakhir saya, dan juga sebagian besar jawaban di sini, gunakan semacam cara setengah statistik untuk memperoleh hasil tipe lonceng-lonceng. Kode yang saya berikan di bawah berfungsi dengan cara yang sama seperti ketika Anda melempar dadu. Oleh karena itu, paling sulit untuk mendapatkan 1 atau 99, tetapi paling mudah untuk mendapatkan 50.

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>

lihat roda
sumber
6

Saya akan merekomendasikan menggunakan distribusi beta untuk menghasilkan angka antara 0-1, kemudian meningkatkannya. Ini cukup fleksibel dan dapat membuat berbagai bentuk distribusi.

Berikut sampler cepat dan kotor:

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

Solusi terbaik yang menargetkan masalah ini adalah yang diusulkan oleh BlueRaja - Danny Pflughoeft tetapi saya pikir solusi yang agak lebih cepat dan lebih umum juga perlu disebutkan.


Ketika saya harus menghasilkan angka acak (string, pasangan koordinat, dll.) Memenuhi dua persyaratan

  1. Hasil yang ditetapkan cukup kecil. (tidak lebih besar dari angka 16K)
  2. Set hasil bersifat rahasia. (seperti bilangan bulat saja)

Saya biasanya mulai dengan membuat array angka (string, pasangan koordinat, dll.) Memenuhi persyaratan (Dalam kasus Anda: array angka yang berisi kemungkinan lebih banyak beberapa kali.), Lalu pilih item acak dari array itu. Dengan cara ini, Anda hanya perlu memanggil fungsi acak mahal satu kali per item.

mg30rg
sumber
1
Jika Anda akan memilih array pilihan, Anda juga dapat mengocoknya setelahnya. Maka Anda bisa mengambilnya secara berurutan sampai Anda kehabisan. Kocok lagi jika / ketika Anda menekan akhir daftar.
Geobits
@ Geobits Mengacak daftar adalah tugas yang jauh lebih banyak sumber daya kemudian secara acak memilih salah satu elemennya. Ini hanya pilihan yang baik jika daftar harus dapat diprediksi.
mg30rg
1
Tetapi Anda hanya melakukannya satu kali per siklus dari daftar, bukan setiap waktu. Jika Anda preprocess ini (karena Anda memiliki langkah preprocessing, saya menganggap itu baik-baik saja), maka sangat cepat untuk mendapatkan setiap nomor sesudahnya. Anda dapat melakukan perombakan ulang setiap kali Anda memiliki waktu henti, atau tahu Anda tidak akan membutuhkan nomor acak sedikit pun. Hanya menawarkannya sebagai alternatif, keduanya memiliki (dis) keuntungan.
Geobits
@ Geobits Jika Anda melakukannya dengan cara Anda, angka "probabilitas tunggal" akan "jatuh" dan sampai resuffling hasilnya tidak dapat muncul. (yaitu jika Anda mensimulasikan pelemparan dua dadu, Anda tidak akan memiliki kesempatan sedikit pun untuk mendapatkan nomor 2 lebih dari dua kali.)
mg30rg
1
Itu alasan yang jauh lebih baik untuk tidak menggunakannya, kecuali untuk aplikasi langka di mana tidak apa-apa;)
Geobits
4

Distribusi

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

Larutan

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

Solusi Umum

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
sumber
4

Anda dapat menggunakan nomor acak pembantu untuk menghasilkan angka acak di 40-60 atau 1-100:

// 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
sumber
4

Jika Anda dapat menggunakan gaussianfungsinya, gunakan itu. Fungsi ini mengembalikan angka normal dengan average 0dan sigma 1.

95% dari jumlah ini ada di dalam average +/- 2*sigma. Anda average = 50, dan sigma = 5sebagainya

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

Cara terbaik untuk melakukan itu adalah menghasilkan angka acak yang didistribusikan secara merata dalam satu set angka tertentu, dan kemudian menerapkan fungsi proyeksi ke set antara 0 dan 100 di mana proyeksi lebih mungkin mengenai angka yang Anda inginkan.

Biasanya cara matematika untuk mencapai ini adalah merencanakan fungsi probabilitas dari angka yang Anda inginkan. Kita bisa menggunakan kurva lonceng, tetapi mari kita demi perhitungan yang lebih mudah, hanya bekerja dengan parabola terbalik.

Mari kita membuat parabola sedemikian rupa sehingga akarnya berada pada 0 dan 100 tanpa mencondongkannya. Kami mendapatkan persamaan berikut:

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

Sekarang, semua area di bawah kurva antara 0 dan 100 mewakili set pertama kami di mana kami ingin angka yang dihasilkan. Di sana, generasi ini sepenuhnya acak. Jadi, yang perlu kita lakukan adalah menemukan batasan set pertama kita.

Batas bawah, tentu saja, 0. Batas atas adalah integral dari fungsi kami di 100, yaitu

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)

Jadi kita tahu bahwa kita perlu membuat angka di suatu tempat antara 0 dan 166.666. Kemudian, kita hanya perlu mengambil nomor itu dan memproyeksikannya ke set kedua kita, yaitu antara 0 dan 100.

Kita tahu bahwa angka acak yang kita hasilkan adalah beberapa integral dari parabola kita dengan input x antara 0 dan 100. Itu berarti kita hanya harus berasumsi bahwa angka acak adalah hasil dari F (x), dan pecahkan untuk x.

Dalam hal ini, F (x) adalah persamaan kubik, dan dalam bentuk F(x) = ax^3 + bx^2 + cx + d = 0, pernyataan berikut ini benar:

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

Memecahkan ini untuk x menghasilkan Anda angka acak aktual yang Anda cari, yang dijamin berada dalam kisaran [0, 100] dan kemungkinan jauh lebih dekat dengan pusat daripada tepi.

arik
sumber
3

Jawaban ini sangat bagus . Tetapi saya ingin memposting instruksi implementasi (saya tidak ke dalam JavaScript, jadi saya harap Anda akan mengerti) untuk situasi yang berbeda.


Asumsikan Anda memiliki rentang dan bobot untuk setiap rentang:

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

Informasi Statis Awal, dapat di-cache:

  1. Jumlah semua bobot (108 sampel)
  2. Batas pemilihan rentang. Ini pada dasarnya rumus ini: Boundary[n] = Boundary[n - 1] + weigh[n - 1]dan Boundary[0] = 0. Sampel sudahBoundary = {0, 1, 3, 103, 108}

Generasi nomor:

  1. Hasilkan angka acak Ndari rentang [0, Jumlah semua bobot).
  2. for (i = 0; i < size(Boundary) && N > Boundary[i + 1]; ++i)
  3. Ambil ikisaran th dan hasilkan angka acak dalam kisaran itu.

Catatan tambahan untuk optimalisasi kinerja. Kisaran tidak harus dipesan baik urutan naik atau turun, jadi untuk rentang look-up rentang yang lebih cepat yang memiliki bobot tertinggi harus diutamakan dan yang dengan bobot terendah harus berada di urutan terakhir.

ST3
sumber