- 例如,现在有40个数字,这40个数字取40到75范围内的随机数,但是这40个随机数的平均值要满足一定是
等于我给死的一个平均数,例如63。 - 开始的思路是先生成39个,然后根据平均数取得第40个随机数,但是这样的话第40个数字就会不在规定的40到
75这个范围内了。 - 望好心人解答
看你的需求。
有很简单的但是随机性差点的做法,比如你第一个随机的数是 A,那么下一个数你就直接得 abs(avg - A),只要是偶数个那么平均值就一定是给定的 avg。
谢谢各位的回答,我还是采用了先随机出前几位,然后留出最后一个数字,根据平均数去算出最后一个数字的值,如果不在这个范围内的话,就递归再次随机,直到随机出在这个范围的数字。
谢谢各位的帮忙!
40个数,均值需要是63
那这40个数的总和就要是2520
那问题就是,从40~75之间选取40个数,和是2520
const selectScope = [40, 75]
const targetAvg = 63
const selectCount = 40
const selectSum=targetAvg*selectCount
那就变成了约束随机问题:随机数之和为S的N个随机数
不要用常规思维来做这件事情, 你是用计算机, 不要怕麻烦, 既然是随机数, 就得随机得彻底.
比如: 你随机40个, 算平均值, 不是你要的, 就再随机, 直到随机的40个数的平均值是你要的为止.
参考一下这个, 还有很大的优化空间, 你可以试试改进
function randomInt(a,b){
return Math.min(a,b) + Math.round(Math.abs(a-b) * Math.random())
}
function sum(a,b){
return a + b;
}
function randomInts(min,max,length,average){
var rfn = randomInt.bind(null,min,max);
var arr = [];
while(arr.length < length){
arr.push(rfn());
}
while(arr.reduce(sum)/length != average){
arr.shift();
arr.push(rfn());
}
return arr;
}
var arr = randomInts(40,75,40,63);
-------------------------补充-------------------------
比较闲,我好事做到底, 优化后一下算法如下:
var _c1=0,_c2=0; //统计随机次数用.
//randomInt 拆成两个 方便比较两种算法.
function randomInt_(a,b){
_c1++;
return Math.min(a,b) + Math.round(Math.abs(a-b) * Math.random())
}
function randomInt(a,b){
_c2++;
return Math.min(a,b) + Math.round(Math.abs(a-b) * Math.random())
}
function sum(a,b){
return a + b;
}
//旧算法
function randomInts1(min,max,length,average){
var rfn = randomInt_.bind(null,min,max);
var arr = [];
while(arr.length < length){
arr.push(rfn());
}
while(arr.reduce(sum)/length != average){
arr.shift();
arr.push(rfn());
}
return arr;
}
//改进算法
function randomInts2(min,max,length,average){
var arr = [];
var k = 0; //与平均数的偏移值
// var _sum = 0;
if(average>max || average<min) throw '参数错误!';
function _autoRandom(){
if(k > 0){
return randomInt(min,average)
}else if(k < 0){
return randomInt(average,max);
}else{
return randomInt(min,max);
}
}
function add(){
var _n = _autoRandom();
k += _n - average;
// _sum += _n;
arr.push(_n);
}
while(arr.length < length){
add();
}
while(k != 0){
var _s = arr.shift();
// _sum -= _s;
k -= _s - average;
add();
}
return arr;
}
//比较两种算法
function test(a,b,c,d){
console.log(`--取${c}个值,平均数为${d}--`);
var arr1 = randomInts1(a,b,c,d);
console.log('arr1 平均值:', arr1.reduce(sum)/c, ' 随机次数:',_c1);
_c1 = 0;
var arr2 = randomInts2(a,b,c,d);
console.log('arr2 平均值:', arr2.reduce(sum)/c, ' 随机次数:',_c2);
_c2 = 0;
}
test(40,75,40, 63);
/*
--取40个值,平均数为63--
arr1 平均值: 63 随机次数: 21147
arr2 平均值: 63 随机次数: 54
*/
稍微优化一下,差距不小.
13 回答12.6k 阅读
7 回答1.7k 阅读
3 回答1k 阅读✓ 已解决
3 回答1.2k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
2 回答1.8k 阅读
2 回答1k 阅读✓ 已解决
你不要描述的这么麻烦,什么40个随机数的平均值是个固定值你换一种想法,这40个随机数的和是个固定值,这不就是微信红包算法吗?简单了吧
还限制范围的话就不能用微信抢红包的方法了,这限制范围的同时还限制随机数的和,那范围内的数字概率就肯定不等了,不限定每个数的概率的话是有无数种方法的
改一改微信抢红包的方法应该是可以的,思路就是随机数一个一个生成,根据剩余的和来决定下一个随机数的生成概率分布
(微信红包先抢后抢的概率分布是不一样的,数学期望是相等的)