2

there's a question. I need to generate random numbers with ranges and each range has a fixed probability like this:

100 - 500      (75%)
501 - 5000     (20%)
10001 - 50000  (4%)
50001 - 100000 (1%)

I have no idea how should i do...

function getRandomAmount() {
  const probabilities = [0.75, 0.2, 0.04, 0.01];
  const items = []
  // 100 - 5000 75%
  // 5001 - 10000 20%
  // 10001 - 50000 4%
  // 50001 - 100000 1%
}
tommm2
  • 31
  • 2
  • Voted reopen because dupes mostly focus on weighted probabilities on a single result. I think that in your case you can combine [this trick](https://stackoverflow.com/a/8877292/4165552) followed by random number from uniform distribution defined inside one of your ranges. But I am not a javascript expert, so no code provided. – pptaszni Nov 03 '22 at 14:52

2 Answers2

0

I think i would do this using objects to represent ranges and probabilities.

Get the range with the random probability and then generate a random number using the max and min of the range

const ranges = [{
  prob: 0.75,
  min: 100,
  max: 5000
},
{
  prob: 0.2,
  min: 5001,
  max: 10000
},
{
  prob: 0.04,
  min: 10001,
  max: 50000
},
{
  prob: 0.01,
  min: 50001,
  max: 100000
}]

function getRandomAmount() {
  const rand = Math.random()
  const range = getRange(rand)
  
  return Math.floor(Math.random() * (range.max - range.min + 1) + range.min)
}

function getRange(rand) {
  return ranges.reduce((acc, curr) => {
    if(acc.total > rand) return acc
    else return {currentRange: curr, total: acc.total + curr.prob}
  }, {currentRange: undefined, total: 0}).currentRange
}

console.log(getRandomAmount())

Probabilities using this function for each range :

const ranges = [{
  prob: 0.75,
  min: 100,
  max: 5000
},
{
  prob: 0.2,
  min: 5001,
  max: 10000
},
{
  prob: 0.04,
  min: 10001,
  max: 50000
},
{
  prob: 0.01,
  min: 50001,
  max: 100000
}]

function getRandomAmount() {
  const rand = Math.random()
  const range = getRange(rand)
  
  return Math.floor(Math.random() * (range.max - range.min + 1) + range.min)
}

function getRange(rand) {
  return ranges.reduce((acc, curr) => {
    if(acc.total > rand) return acc
    else return {currentRange: curr, total: acc.total + curr.prob}
  }, {currentRange: undefined, total: 0}).currentRange
}

// example using 10000 numbers

const probabilities = [0,0,0,0]
const TOTAL_TRY = 100000

for (let i = 0; i < TOTAL_TRY; i++){
  const rand = getRandomAmount()
  const index = ranges.findIndex(range => range.min < rand && range.max > rand)
  probabilities[index] += 1
}

console.log(probabilities.map((prob, index) => ({index, total: prob, probability: prob/TOTAL_TRY})))
RenaudC5
  • 3,553
  • 1
  • 11
  • 29
0

My approach is probably not as good as the other answer, but I also decided to give it a shot:

const ranges = {
  75: [100, 500],
  20: [501, 5000],
  4: [10001, 50000],
  1: [50001, 100000]
}

const randomNumber = (min, max) => Math.floor(Math.random() * (max - min) + min)

const assignRange = (number) => {
  if (number <= 4 && number > 1) return 4
  if (number <= 20 && number > 4) return 20
  if (number <= 100 && number > 20) return 75
  return 1
}

const getRandomAmount = () => {
  const selectedRange = ranges[assignRange(randomNumber(0, 100))]
  
  return randomNumberRange(selectedRange[0], selectedRange[1])
}
xifre
  • 26
  • 2