寻找适用于所有情况或任何数字的答案。
值也可以是十进制的,例如55.55、10.10等,但总体上将是100%。
尽管您将总重量限制为100,但您希望在该范围内容纳小数值的事实意味着您不能假设最多有100个单位可供选择。如果您的粒度是十分之一,则每个潜在选择的单位将为0.1。如果指定到百分之一(如55.55),则您需要以每次0.01的相对基本单位。
因为我不想通过浮点值进行迭代,所以建议您通过消除权重和随机数生成器中的所有浮点数的因子来扩大所有值——只需乘以10/100/1000等您需要将所有权重转换为整数的因子即可。
现在让我们尽可能地缩短迭代过程:
- 遍历输入数组一次,以确定最长的小数精度。
- 在0到(所有权重之和减1)乘以10的“最长表示小数长度”的幂之间选择一个随机整数。
- 再次遍历输入数组,并简单地检查随机整数是否小于当前权重加上任何先前的权重;如果不是,则中断循环,因为已经找到了所选的加权随机数。
代码:(演示)--演示进行了10次迭代,以帮助揭示加权效果
$valueWeights = [
149 => 55.555,
130 => 10.0050,
131 => 5,
132 => 5.2,
133 => 10,
134 => 10.24,
135 => 5
];
$mostDecimals = 0;
foreach ($valueWeights as $value => $weight) {
$tempDecimals = 0;
while ((string)$weight !== (string)floor($weight)) {
$weight *= 10;
++$tempDecimals;
}
$mostDecimals = max($mostDecimals, $tempDecimals);
}
echo "Most Decimals: {$mostDecimals}\n";
$factor = pow(10, $mostDecimals);
echo "Factor: " , $factor , "\n";
$totalWeight = (array_sum($valueWeights) - 1) * $factor;
for ($i = 0; $i < 10; ++$i) {
$rand = mt_rand(0, $totalWeight);
echo "\nRand: " , $rand , "\n";
$cumulativeScaledWeight = 0;
foreach ($valueWeights as $value => $weight) {
$cumulativeScaledWeight += $weight * $factor;
if ($rand < $cumulativeScaledWeight) {
echo "Value: {$value}\n";
break;
}
}
}
输出:
Most Decimals: 3
Factor: 1000
Rand: 52197
Value: 149
Rand: 33785
Value: 149
Rand: 4783
Value: 149
Rand: 24994
Value: 149
Rand: 76588
Value: 133
Rand: 77417
Value: 133
Rand: 40541
Value: 149
Rand: 80009
Value: 133
Rand: 14826
Value: 149
Rand: 52691
Value: 149
55、10、5
,按比例1:3:3
计算,因此最大结果只能为3
。 - Antony Jack44,10,9,21,36
,对吗? - Jackson