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