รับตัวเลขสุ่มมุ่งเน้นที่ศูนย์


238

เป็นไปได้หรือไม่ที่จะได้รับตัวเลขสุ่มระหว่าง 1-100 และให้ผลลัพธ์ส่วนใหญ่อยู่ในช่วง 40-60 ฉันหมายความว่ามันจะออกนอกช่วงนั้นไม่ค่อยได้ แต่ฉันต้องการให้มันอยู่ในช่วงนั้น ... เป็นไปได้ด้วย JavaScript / jQuery?

Math.random() * 100 + 1ตอนนี้ฉันเพียงแค่ใช้พื้นฐาน





20
ฉันชอบที่คำถามนี้จะไป แต่ฉันคิดว่ามันควรจะเฉพาะเจาะจงมากขึ้น คุณต้องการการกระจายแบบ Z (เส้นโค้งแบบเบลล์) การกระจายแบบสามเหลี่ยมหรือการกระจายแบบฟันเลื่อยหรือไม่? มีความเป็นไปได้หลายอย่างในการตอบคำถามนี้ในความคิดของฉัน
Patrick Roberts

12
สิ่งนี้สามารถทำได้ใน javascript แต่แน่นอนว่าไม่มีส่วนเกี่ยวข้องกับ jQuery ... :)
A. Wolff

คำตอบ:


397

วิธีที่ง่ายที่สุดคือการสร้างตัวเลขสุ่มสองหมายเลขจาก 0-50 และเพิ่มเข้าด้วยกัน

นี่ทำให้การแจกแจงเอนเอียงไปทาง 50 ในทำนองเดียวกันหมุนอคติสองลูกเต๋าไปยัง 7

ในความเป็นจริงโดยการใช้ "ลูกเต๋า" จำนวนมากขึ้น(ตามที่ @Falco แนะนำ)คุณสามารถทำการประมาณให้ใกล้เคียงกับเส้นโค้งระฆัง:

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

ตัวเลขสุ่มแบบถ่วงน้ำหนัก

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


12
นี่เป็นวิธีแก้ปัญหาที่ง่ายและรวดเร็วซึ่งสามารถชั่งน้ำหนักได้ง่ายขึ้นโดยเพิ่มจำนวนมากขึ้นเช่น 4 x (0-25) และจะให้เส้นโค้งระฆังที่ดีสำหรับการแจกแจง!
Falco

8
นี่เป็นโค้ดที่ยอดเยี่ยม ฉันคิดว่าฉันตกหลุมรักมัน ง่ายรวดเร็วมีประสิทธิภาพ คำตอบที่ดี ขอขอบคุณสำหรับการโพสต์นี้.
ctwheels

14
คำตอบที่ยอดเยี่ยม แต่ในกรณีที่ใครตั้งใจจะใช้สิ่งนี้เพื่อสร้างการแจกแจงแบบปกติมันไม่มีประสิทธิภาพเลยทีเดียว (และคุณต้องแปลงมันให้ได้ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานที่ต้องการ) ตัวเลือกที่มีประสิทธิภาพมากขึ้นคือการแปลง Box-Muller ซึ่งค่อนข้างง่ายต่อการนำไปใช้และทำความเข้าใจถ้าคุณรู้คณิตศาสตร์บ้าง
Brendon

1
@RaziShaban มันใช้งานง่ายมาก: มีเพียงการผสมผสานของการขว้างลูกตายที่รวมกันได้มากถึง 2 (แค่ดวงตางู) แต่มี 6 ชุดที่แตกต่างกันที่รวมกันได้ถึง 7 (6-1, 5-2, 4-3, 3- 4, 2-5, 1-6) หากคุณพูดถึงลูกเต๋าแบบ N ด้านค่าสูงสุดจะเป็น N + 1 เสมอ
Barmar

2
@RaziShaban การศึกษาตัวแปรแบบสุ่มเป็นส่วนสำคัญของสถิติ ความจริงที่ว่าในขณะที่เราเพิ่มลูกเต๋าที่เราเข้าใกล้การแจกแจงแบบปกติที่มีชื่อเสียงทฤษฎีขีด จำกัด กลาง
BlueRaja - Danny Pflughoeft

48

คุณมีคำตอบที่ดีที่นี่ที่ให้การแก้ปัญหาเฉพาะ ให้ฉันอธิบายให้คุณแก้ปัญหาทั่วไป ปัญหาคือ:

  • ฉันมีแหล่งที่มาของตัวเลขสุ่มกระจายมากกว่าหรือน้อยกว่าอย่างสม่ำเสมอระหว่าง 0 และ 1
  • ฉันต้องการสร้างลำดับของตัวเลขสุ่มที่เป็นไปตามการแจกแจงที่แตกต่างกัน

วิธีแก้ปัญหาทั่วไปสำหรับปัญหานี้คือการหาฟังก์ชั่นควอไทล์ของการกระจายตัวที่คุณต้องการแล้วใช้ฟังก์ชั่นควอไทล์กับเอาท์พุทของแหล่งกำเนิดเครื่องแบบของคุณ

ฟังก์ชั่น quantile เป็นผกผันของหนึ่งที่คุณต้องการฟังก์ชั่นการจัดจำหน่าย ฟังก์ชันการแจกแจงคือฟังก์ชันที่พื้นที่ใต้ส่วนของเส้นโค้งเท่ากับความน่าจะเป็นที่รายการที่สุ่มเลือกจะอยู่ในส่วนนั้น

ฉันยกตัวอย่างวิธีการทำที่นี่:

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

รหัสในนั้นมีใน C # แต่หลักการใช้กับภาษาใด ๆ มันควรจะตรงไปตรงมาเพื่อปรับแก้ปัญหากับ JavaScript


2
ฉันชอบวิธีนี้ อาจต้องการเพิ่มว่ามีไลบรารี javascript ที่สร้างการแจกแจงแบบเกาส์ (และอื่น ๆ ที่ไม่ปกติ): simjs.com/random.html
Floris

36

การใช้อาร์เรย์ของตัวเลข ฯลฯ ไม่มีประสิทธิภาพ คุณควรทำการแมปซึ่งใช้ตัวเลขสุ่มระหว่าง 0 ถึง 100 และแมปไปยังการกระจายที่คุณต้องการ ดังนั้นในกรณีของคุณคุณสามารถรับการกระจายที่มีค่ามากที่สุดในช่วงกลางของคุณf(x)=-(1/25)x2+4x

การกระจาย


2
เราไม่รู้จริง ๆ ว่าต้องการการกระจายแบบใด "ส่วนใหญ่ 40-60" หมายถึงเส้นโค้งระฆังสำหรับฉัน
ถนัดมือ

ใช่คุณพูดถูกบางทีคุณอาจต้องการแผนที่ที่ดีกว่านี้ แต่นั่นสำคัญมาก
iCaramba

3
ฉันจะใช้คำพูดของคุณเพราะสิ่งนี้ไม่ใช่ความเชี่ยวชาญของฉัน คุณสามารถปรับฟังก์ชั่นและแสดงเส้นโค้งใหม่ได้หรือไม่?
ถนัดมือ

1
@Lefty - เส้นโค้งระฆังแบบง่ายสำหรับxระหว่าง 0 และ 100 (นำมาจากคำถามนี้ ):y = (Math.sin(2 * Math.PI * (x/100 - 1/4)) + 1) / 2
Sphinxxx

@Sphinxxx นั่นไม่ใช่เส้นโค้งระฆังมันเป็นเส้นโค้งบาป เส้นโค้งรูประฆังจะไม่สัมผัสกับแกน x
BlueRaja - Danny Pflughoeft

17

ฉันอาจทำบางสิ่งเช่นตั้งค่า "โอกาส" เพื่อให้หมายเลขอนุญาตให้ "เกินขอบเขต" ในตัวอย่างนี้มีโอกาส 20% จำนวนจะเป็น 1-100 มิฉะนั้น 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>

ซอ: http://jsfiddle.net/kbv39s9w/


5
บางทีคนที่มีรายละเอียดทางสถิติมากกว่านี้ก็สามารถแก้ไขฉันได้และถึงแม้ว่าสิ่งนี้จะบรรลุสิ่งที่ OP กำลังมองหา (ดังนั้นฉันจึงลงคะแนน) แต่นี่จะไม่เลือก # out of ขอบเขต 20% ของเวลาใช่ไหม? ในโซลูชันนี้ 20% ของเวลาที่คุณจะมีโอกาสเลือก # จาก 1-100 ซึ่งรวม 40-60 สิ่งนี้จะไม่เป็นจริงหรือไม่ (0.2 * 0.8) 16% ในการเลือก # นอกขอบเขตหรือว่าฉันขาดอะไรไป?
Josh

ไม่ถูกต้อง มันเป็นเพียงถ้อยคำของฉัน ฉันจะแก้ไขมัน ขอบคุณ!
Bitwise Creative

1
@ Josh - นั่นเป็นจุดที่สวย นี่คือหลักฐานที่เรียบง่ายของสิ่งที่มีลักษณะที่เหมือนjsfiddle.net/v51z8sd5 จะแสดงเปอร์เซ็นต์ของจำนวนที่พบนอกขอบเขตและวนรอบ 0.16 (16%)
Travis J

15

ฉันต้องแก้ปัญหานี้เมื่อไม่กี่ปีที่ผ่านมาและวิธีการแก้ปัญหาของฉันก็ง่ายกว่าคำตอบอื่น ๆ

ฉันสร้าง 3 randoms ระหว่างขอบเขตและค่าเฉลี่ย สิ่งนี้จะดึงผลลัพธ์ไปยังศูนย์กลาง แต่ปล่อยให้มันไปได้จนสุดความสามารถ


7
สิ่งนี้ดีกว่า / แตกต่างจากคำตอบของ BlueRaja อย่างไร ที่นั่นเขารับผลรวมของ (2,3, ... จำนวนที่คุณต้องการ) ตัวเลขสุ่มและใช้ค่าเฉลี่ย ผลลัพธ์จะเหมือนกับของคุณเมื่อคุณใช้แบบBellFactor3
Floris

@ ภูเขาน้ำแข็งดีฉันไม่ได้เขียนโค้ดในตระกูลภาษา c ดังนั้นคำตอบนั้นไม่ได้ดูราวกับว่ามันกำลังทำสิ่งเดียวกันกับคำตอบของฉันจนกว่าฉันจะอ่านซ้ำตอนนี้ ฉันสร้างวิธีการของฉันโดยการทดลองและข้อผิดพลาดเล็กน้อยและพบว่า 3 randoms เป็นจำนวนที่เหมาะสม นอกจากนี้การขุดสามารถทำได้ในหนึ่งบรรทัดและยังง่ายต่อการเข้าใจ
Lefty

2
จริงๆ? คุณไม่คิดว่า JS และ C มีความคล้ายคลึงกันไหม? ตกลงเอาล่ะบอกว่าฉันไม่สามารถพูดภาษา EITHER ได้ทั้งภาษาและ Java ซึ่งสำหรับฉันนั้นมีความคล้ายคลึงกันเมื่อเทียบกับภาษาที่ฉันคุ้นเคย
Lefty

1
จุดที่เป็นธรรมฉันถูกดึงดูดโดยเฉพาะชื่อเป็นสิ่งที่ฉันได้แก้ไขตัวเองและค่อนข้างภูมิใจในวิธีที่ฉันทำมัน อีกครั้งฉันไม่รู้ว่ามันเป็นคำถาม js จนกว่าคุณจะพูดอย่างนั้น โชคดีจริงๆเพราะเทคนิคของฉันไม่ได้ขึ้นอยู่กับภาษาและบางคนคิดว่ามันเป็นคำตอบที่มีประโยชน์
ถนัดมือ

5
JavaScript เป็นภาษา C-family จริงๆ ... แต่ก็ดี
Joren

14

มันดูโง่ แต่คุณสามารถใช้ Rand ครั้งที่สอง:

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

11

แน่นอนว่าเป็นไปได้ ทำการสุ่ม 1-100 ถ้าตัวเลขเป็น <30 ให้สร้างตัวเลขในช่วง 1-100 ถ้าไม่สร้างในช่วง 40-60


11

มีหลายวิธีในการสร้างตัวเลขสุ่มดังกล่าว วิธีหนึ่งที่จะทำได้คือการคำนวณผลรวมของตัวเลขสุ่มหลายชุดอย่างสม่ำเสมอ คุณสุ่มตัวเลขจำนวนเท่าใดและช่วงใดที่จะเป็นตัวกำหนดว่าการแจกแจงสุดท้ายจะเป็นอย่างไร

ยิ่งคุณสรุปจำนวนมากเท่าไหร่ก็จะยิ่งมีอคติมากขึ้นเท่านั้น การใช้ผลรวมของตัวเลขสุ่ม 1 ข้อได้ถูกเสนอในคำถามของคุณแล้ว แต่เมื่อคุณสังเกตเห็นว่าไม่ได้มีอคติไปยังกึ่งกลางของช่วง คำตอบอื่น ๆ ได้เสนอโดยใช้ผลรวมของตัวเลขสุ่ม 2 ตัวหรือผลรวมของตัวเลขสุ่ม 3 ตัวตัวเลขสุ่ม

คุณสามารถให้ความลำเอียงเข้าหาจุดกึ่งกลางของช่วงได้มากขึ้นโดยการหาผลรวมของตัวเลขสุ่มมากขึ้น สุดขีดคุณสามารถนำผลรวมของตัวเลขสุ่ม 99 หมายเลขซึ่งแต่ละอันมีค่า 0 หรือ 1 นั่นจะเป็นการกระจายแบบทวินาม (การแจกแจงแบบทวินามสามารถรับรู้ได้ว่าเป็นการแจกแจงแบบปกติโดยสิ้นเชิง) สิ่งนี้ยังคงอยู่ในทฤษฎีครอบคลุมเต็มรูปแบบ แต่มีอคติต่อศูนย์ที่คุณไม่ควรคาดหวังว่าจะเห็นจุดสิ้นสุด

วิธีการนี้หมายความว่าคุณสามารถปรับแต่งอคติที่คุณต้องการได้


8

เกี่ยวกับการใช้สิ่งนี้:

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>

วิธีที่ฉันเขียนมันช่วยให้คุณตั้งค่าตัวแปรได้สองแบบ:
วนซ้ำ = จำนวนผลลัพธ์ที่ได้
ลอง = จำนวนครั้งที่ฟังก์ชันจะพยายามรับตัวเลขระหว่าง 40-60 ก่อนที่มันจะหยุดทำงานในขณะที่วนซ้ำ

โบนัสเพิ่มเติม: มันใช้ทำในขณะที่ !!! ยอดเยี่ยมที่สุด


8

คุณสามารถเขียนฟังก์ชั่นที่แมปค่าสุ่มระหว่าง[0, 1)ถึง[1, 100]ตามน้ำหนัก ลองพิจารณาตัวอย่างนี้:

0.0-1.0 ถึง 1-100 โดยน้ำหนักเป็นเปอร์เซ็นต์

นี่ค่าแมปกับค่าระหว่าง0.95 ในความเป็นจริงเรามีซึ่งเมื่อแมปกับผลผลิต[61, 100]
.05 / .1 = 0.5[61, 100]81อัตราผลตอบแทน

นี่คือฟังก์ชั่น:

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


7

นี่คือวิธีแก้ปัญหาแบบถ่วงน้ำหนักที่ 3/4 40-60 และ 1/4 อยู่นอกช่วงนั้น

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>


6

ตกลงดังนั้นฉันตัดสินใจที่จะเพิ่มคำตอบอื่น ๆ เพราะฉันรู้สึกเหมือนคำตอบสุดท้ายของฉันเช่นเดียวกับคำตอบส่วนใหญ่ที่นี่ให้ใช้วิธีการทางสถิติครึ่งหนึ่งในการรับผลตอบแทนประเภทระฆังโค้ง รหัสที่ฉันให้ด้านล่างทำงานในลักษณะเดียวกับเมื่อคุณหมุนลูกเต๋า ดังนั้นจึงเป็นการยากที่จะได้ 1 หรือ 99 แต่ง่ายที่สุดที่จะได้ 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>


6

ฉันขอแนะนำให้ใช้การกระจายเบต้าเพื่อสร้างตัวเลขระหว่าง 0-1 จากนั้นขยายขนาด มันค่อนข้างยืดหยุ่นและสามารถสร้างรูปทรงต่าง ๆ มากมาย

นี่คือตัวอย่างรวดเร็วและสกปรก:

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

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

5

ทางออกที่ดีที่สุดที่กำหนดเป้าหมายของปัญหานี้คือสิ่งที่เสนอโดยBlueRaja - Danny Pflughoeftแต่ฉันคิดว่าวิธีแก้ปัญหาที่ค่อนข้างเร็วกว่าและทั่วไปกว่านั้นก็น่าสนใจเช่นกัน


เมื่อฉันต้องสร้างตัวเลขสุ่ม (สตริงคู่ประสานงาน ฯลฯ ) ที่สอดคล้องกับข้อกำหนดสองข้อของ

  1. ชุดผลลัพธ์ค่อนข้างเล็ก (ไม่เกิน 16K หมายเลข)
  2. ชุดผลลัพธ์นั้นรอบคอบ (เช่นตัวเลขจำนวนเต็มเท่านั้น)

ฉันมักจะเริ่มต้นด้วยการสร้างอาร์เรย์ของตัวเลข (สตริงคู่ประสานงาน ฯลฯ ) ตอบสนองความต้องการ (ในกรณีของคุณ: อาร์เรย์ของตัวเลขที่มีคนน่าจะเป็นหลาย ๆ ครั้ง) จากนั้นเลือกรายการสุ่มของอาร์เรย์นั้น ด้วยวิธีนี้คุณจะต้องเรียกฟังก์ชั่นการสุ่มราคาแพงหนึ่งครั้งต่อรายการ


1
หากคุณกำลังเตรียมตัวเลือกมากมายไว้ล่วงหน้าคุณอาจสับเปลี่ยนตัวเลือกเหล่านั้นในภายหลัง จากนั้นคุณสามารถคว้าพวกเขาตามลำดับจนกว่าคุณจะหมด สุ่มอีกครั้งหาก / เมื่อคุณกดจุดสิ้นสุดของรายการ
Geobits

@Geobits การสลับรายการเป็นงานที่ใช้ทรัพยากรมากขึ้นจากนั้นจึงสุ่มเลือกองค์ประกอบใดรายการหนึ่ง มันเป็นทางเลือกที่ดีถ้ารายการต้องคาดเดาได้
mg30rg

1
แต่คุณทำเพียงครั้งเดียวต่อหนึ่งรอบของรายการแทนที่จะเป็นทุกครั้ง หากคุณทำการประมวลผลล่วงหน้า (เนื่องจากคุณมีขั้นตอนการประมวลผลล่วงหน้าอยู่ดีฉันถือว่ามันดี) แล้วมันก็เร็วมากที่จะรับหมายเลขแต่ละหมายเลขหลังจากนั้น คุณสามารถสับเปลี่ยนเมื่อใดก็ตามที่คุณมีเวลาหยุดทำงานหรือรู้ว่าคุณไม่ต้องการตัวเลขสุ่มสักเล็กน้อย เพียงแค่เสนอเป็นทางเลือกทั้งสองมีข้อดี (dis)
Geobits

@Geobits หากคุณทำตามที่คุณต้องการตัวเลข "ความน่าจะเป็นเดี่ยว" จะ "หลุด" และจนกว่าจะมีการ resuffling พวกเขาจะไม่เกิดขึ้นอีก (เช่นถ้าคุณจำลองการขว้างปาของสองสี่เหลี่ยมลูกเต๋าที่คุณจะไม่ได้มีโอกาสน้อยที่จะได้รับจำนวน 2 มากกว่าสองครั้ง.)
mg30rg

1
นั่นเป็นเหตุผลที่ดีกว่ามากที่จะไม่ใช้มันยกเว้นแอพพลิเคชั่นที่หายากซึ่งมันก็โอเค)
Geobits

4

การกระจาย

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

สารละลาย

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

โซลูชันทั่วไป

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

4

คุณสามารถใช้หมายเลขสุ่มตัวช่วยเพื่อสร้างตัวเลขสุ่มใน 40-60 หรือ 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);
}


4

หากคุณสามารถใช้gaussianฟังก์ชั่นใช้งานได้ ฟังก์ชั่นนี้จะส่งกลับจำนวนปกติและaverage 0sigma 1

95% average +/- 2*sigmaของจำนวนนี้อยู่ใน ของคุณaverage = 50และsigma = 5อื่น ๆ

randomNumber = 50 + 5*gaussian()

3

วิธีที่ดีที่สุดในการทำเช่นนั้นคือการสร้างตัวเลขสุ่มที่กระจายอย่างเท่าเทียมกันในชุดตัวเลขจำนวนหนึ่งจากนั้นใช้ฟังก์ชั่นการฉายภาพกับชุดระหว่าง 0 และ 100 ที่การฉายภาพมีแนวโน้มที่จะตีตัวเลขที่คุณต้องการ

โดยทั่วไปแล้ววิธีทางคณิตศาสตร์ในการบรรลุเป้าหมายนี้คือการวางแผนฟังก์ชันความน่าจะเป็นของตัวเลขที่คุณต้องการ เราสามารถใช้เส้นโค้งรูประฆังได้ แต่เพื่อให้การคำนวณง่ายขึ้นเพียงแค่ทำงานกับพาราโบลาที่พลิกกลับ

ลองสร้างพาราโบลาแบบที่รากของมันอยู่ที่ 0 และ 100 โดยไม่บิดเบือนมัน เราได้สมการต่อไปนี้:

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

ตอนนี้พื้นที่ทั้งหมดภายใต้เส้นโค้งระหว่าง 0 ถึง 100 เป็นตัวแทนของชุดแรกของเราที่เราต้องการสร้างตัวเลข ที่นั่นรุ่นนั้นสุ่มอย่างสมบูรณ์ ดังนั้นสิ่งที่เราต้องทำคือหาขอบเขตของเซตแรกของเรา

แน่นอนว่าขอบเขตล่างคือ 0 ขอบเขตบนคือส่วนประกอบของฟังก์ชันที่ 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)

ดังนั้นเรารู้ว่าเราจำเป็นต้องสร้างตัวเลขระหว่าง 0 ถึง 166,666 จากนั้นเราเพียงแค่นำหมายเลขนั้นมาฉายในเซตที่สองของเราซึ่งอยู่ระหว่าง 0 ถึง 100

เรารู้ว่าตัวเลขสุ่มที่เราสร้างขึ้นนั้นเป็นส่วนหนึ่งของพาราโบลาของเราด้วยอินพุต x ระหว่าง 0 และ 100 นั่นหมายความว่าเราต้องสมมติว่าตัวเลขสุ่มนั้นเป็นผลลัพธ์ของ F (x) และแก้หา x

ในกรณีนี้ F (x) เป็นสมการลูกบาศก์และในรูปแบบF(x) = ax^3 + bx^2 + cx + d = 0ข้อความต่อไปนี้เป็นจริง:

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

การแก้ปัญหานี้สำหรับ x ทำให้คุณได้จำนวนสุ่มที่คุณต้องการซึ่งรับประกันได้ว่าอยู่ในช่วง [0, 100] และมีโอกาสสูงที่จะอยู่ใกล้กับศูนย์กลางมากกว่าขอบ


3

คำตอบนี้เป็นสิ่งที่ดีจริงๆ แต่ฉันต้องการโพสต์คำแนะนำการใช้งาน (ฉันไม่ได้อยู่ใน JavaScript ดังนั้นฉันหวังว่าคุณจะเข้าใจ) สำหรับสถานการณ์ที่แตกต่างกัน


สมมติว่าคุณมีช่วงและน้ำหนักสำหรับทุกช่วง:

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

ข้อมูลคงที่เริ่มต้นอาจถูกแคช:

  1. ผลรวมของน้ำหนักทั้งหมด (108 ตัวอย่าง)
  2. ขอบเขตการเลือกช่วง มันเป็นพื้นสูตรนี้และBoundary[n] = Boundary[n - 1] + weigh[n - 1] Boundary[0] = 0ตัวอย่างมีBoundary = {0, 1, 3, 103, 108}

การสร้างจำนวน:

  1. สร้างตัวเลขสุ่มNจากช่วง [0, ผลรวมของน้ำหนักทั้งหมด)
  2. for (i = 0; i < size(Boundary) && N > Boundary[i + 1]; ++i)
  3. ใช้iช่วงที่ th และสร้างตัวเลขสุ่มในช่วงนั้น

หมายเหตุเพิ่มเติมสำหรับการเพิ่มประสิทธิภาพ ไม่จำเป็นต้องสั่งช่วงไม่ว่าจะขึ้นหรือลงเพื่อดังนั้นสำหรับช่วงการค้นหาที่เร็วขึ้นที่มีน้ำหนักสูงสุดควรจะไปก่อนและอีกอันที่น้ำหนักต่ำสุดควรจะอยู่ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.