随机生成器Rand9()使用Rand3()

时间:2015-04-21 13:23:02

标签: algorithm random

如何使用生成1到3之间数字的函数生成1到9之间的数字?获得1到9之间任何数字的概率必须相同,因此rand3()+ rand3()+ rand3()不是一个好的解决方案。

2 个答案:

答案 0 :(得分:4)

尝试类似笛卡尔的产品:

Rand9() = 3 * (Rand3() - 1) + Rand3()

使用3 *(Rand3() - 1),您可以同样地生成子区间1-3,4-6和7-9。使用+ Rand3(),您将在该子间隔上同等选择。

作为产品撰写:

3 * (Rand3() - 1) + Rand3() -> {1, 4, 7} X {+1,+2,+3} -> {1,2,3,4,5,6,7,8,9}

答案 1 :(得分:1)

该解决方案的主要思想是构建3*3矩阵。

[
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

function init() {
  const rand3 = generateMathRandom(3);
  let randFunc = rand3;
  const start = 9;
  const end = 10;

  let i = start;
  
  console.time('---start');
  while (i < end) {
    randFunc = generateRandom(i, 3, rand3);
    healthCheck(i, randFunc);
    i++;
  }
  console.timeEnd('---start');
  
  i = start;
  console.time('---start-math');
  while (i < end) {
    randFunc = generateMathRandom(i);
    healthCheck(i, randFunc);
    i++;
  }
  console.timeEnd('---start-math');
}

function generateMathRandom(range) {
  return function () {
    return Math.floor(Math.random() * range);
  }
}

// range - target random range number : e.g 9
// lowerRange - base random range number : e.g 3
// func - function which generate random with the range of lowerRange : e.g rand3
function generateRandom(range, lowerRange, func) {
  return function () {
    const results = [];
    let times = 1;
    let matRange = lowerRange;
    let mat = Math.sqrt(range);
    while(mat > lowerRange) {
      mat = Math.sqrt(mat);
      times ++;
      matRange *= lowerRange;
    }
    const noneStart = Math.floor(matRange * matRange / range) * range;

    for (let i = 0; i < matRange; i++) {
      results.push([]);
      for (let j = 0; j < matRange; j++) {
        const num = i * matRange + j;
        if (num < noneStart)
          results[i].push(num % range);
        else
          results[i].push(-1);
      }
    }

    while (true) {
      const row = new Array(times).fill(1).map(n => func()).reduce((a, c) => a * lowerRange + c, 0);
      const col = new Array(times).fill(1).map(n => func()).reduce((a, c) => a * lowerRange + c, 0);
      if (!results[row]) {
        debugger;
      }
      if (results[row][col] == undefined) {
        debugger;
      }

      if (results[row][col] === -1) continue;

      return results[row][col];
    }
  }
}

function healthCheck(range, func = null, count = 100000) {
  const funcToCheck = func || rand[range] || null;
  if (!funcToCheck) {
    console.log('Function is not provided');
    return;
  }

  const health = new Array(range).fill(0);
  const checkCount = count - count % range; // To do correct check.

  for (let i = 0; i < checkCount; i++) {
    health[funcToCheck()]++;
  }

  const result = health.map((cnt, index) => ({
    _value: index,
    rate: (cnt / checkCount * 100).toFixed(5)
  }));
  // console.log('Random result:', result);

  let minRate = 100, maxRate = 0;
  for (let i = 0; i < range; i++) {
    minRate = Math.min(Number(result[i].rate), minRate);
    maxRate = Math.max(Number(result[i].rate), maxRate);
  }
  console.log('Random health<' + range + '>: ' + healthOutput(range, maxRate - minRate));
}

function healthOutput(range, rangeOffset) {
  const healthThreshold = 2; // It should be lower for the best Alghorithms
  const threshold = healthThreshold;
  if (rangeOffset < threshold * 0.2) {
    return 'The Super! -> ' + rangeOffset.toFixed(5);
  } else if (rangeOffset < threshold * 0.5) {
    return 'The Best! --> ' + rangeOffset.toFixed(5);
  } else if (rangeOffset < threshold * 1) {
    return 'Good work! -> ' + rangeOffset.toFixed(5);
  } else if (rangeOffset < threshold * 2) {
    return 'Not bad! ---> ' + rangeOffset.toFixed(5);
  }
  return 'Worst! -----> ' + rangeOffset.toFixed(5);
}

init();