假設100有人和$120。可以將其劃分為每個人獲得某物的亂數量的公式是什么?
在這種情況下,一個人可以獲得任意數量,例如$0.25,某人可以獲得$10,某人可以獲得$1,但每個人都會得到一些東西。有小費嗎?
所以在 Javascript 中,可以生成一個 100 的陣列,這些亂數將在其中,但它們加起來為 100
uj5u.com熱心網友回復:
要使用簡單的方法獲得盡可能少的 1 美分的結果,您可以生成 100 個隨機值,找到它們的總和 S,然后將每個值乘以120.0/Sum四舍五入為整數美分,再次得到總和。如果有多余的(一些美分),則將其分發給隨機的人。
10 人和 12 美元的 Python 示例。1 并overall-num允許避免零金額:
import random
overall = 1200
num = 10
amounts = [random.random() for _ in range(num)]
asum = sum(amounts)
for i in range(num):
amounts[i] = 1 int(amounts[i]*(overall-num) / asum)
asum = sum(amounts)
for i in range(overall - asum):
amounts[random.randint(0,9)] = 1
print(amounts, sum(amounts))
>>[163, 186, 178, 152, 89, 81, 169, 90, 17, 75] 1200
另一種方式(數學意義上的變體的公平分布),正如 Aki Suihkonen 在評論中所注意到的,是使用從分隔位置陣列(帶混洗)中的隨機選擇來實作(我的第一個提議,但我之前認為實作過于復雜):
put 12000 one-cent coins in row
put 99 sticks (dividers) between them, in 11999 spaces between coins
give coins between k and k 1 stick to k-th person
Python實作:
arr = [i for i in range(overall-1)]
divs = [0] sorted(random.choices(arr, k=num-1)) [overall]
amounts = [(divs[i 1]-divs[i]) for i in range(num)]
print(amounts, sum(amounts))
>>>[17, 155, 6, 102, 27, 222, 25, 362, 50, 234] 1200
uj5u.com熱心網友回復:
只是為了提供另一種方法來做到這一點,為每個分配一個亂數,然后歸一化以使總和正確加起來。這應該是相當有效的,O(countPeople)無論我們分多少錢或分得多么細。
這是 JavaScript 中的一個解決方案,如果需要,它還可以處理四舍五入到最接近的一分錢。不幸的是,雖然它不太可能不給錢,但這是可能的。這可以通過每人掏出一分錢并給他們來解決,或者通過測驗您是否沒有分發錢并重新運行來解決。
function distributeRandomly(value, countPeople, roundTo) {
var weights = [];
var total = 0
var i;
// To avoid floating point error, use integer operations.
if (roundTo) {
value = Math.round(value / roundTo);
}
for (i=0; i < countPeople; i ) {
weights[i] = Math.random();
total = weights[i];
}
for (i=0; i < countPeople; i ) {
weights[i] *= value / total;
}
if (roundTo) {
// Round off
total = 0;
for (i = 0; i < countPeople; i ) {
var rounded = Math.floor(weights[i]);
total = weights[i] - rounded;
weights[i] = rounded;
}
total = Math.round(total);
// Distribute the rounding randomly
while (0 < total) {
weights[Math.floor(Math.random(countPeople))] = 1;
total -= 1;
}
// And now normalize
for (i = 0; i < countPeople; i ) {
weights[i] *= roundTo;
}
}
return weights;
}
console.log(distributeRandomly(120, 5));
console.log(distributeRandomly(120, 6, 0.01));
uj5u.com熱心網友回復:
您需要多項式分布。我拆分 12000 而不是 120 以允許美分。
var n = 100;
var probs = Array(n).fill(1/n);
var sum = Array(n).fill(0);
for(var k=0; k < 12000; k ){
var i = -1;
var p = 0;
var u = Math.random();
while(p < u){
i = 1;
p = probs[i];
}
sum[i] = 1;
}
sum = sum.map(function(x){return x/100;});
console.log(sum);
1.26,1.37,1.28,1.44,1.31,1.22,1.2,1.27,1.21,1.37,1.05,1.17,0.98,1.13,1.18,1.44,0.94,1.32,1.03,1.23,1.19,1.13,1.13,1.32,1.36,1.35,1.32,1.04,1.1,1.18,1.18,1.31,1.17,1.13,1.08,1.11,1.19,1.31,1.2,1.1,1.31,1.22,1.15,1.09,1.27,1.14,1.06,1.23,1.21,0.94,1.32,1.13,1.29,1.25,1.13,1.22,1.13,1.13,1.1,1.16,1.12,1.11,1.26,1.21,1.07,1.19,1.07,1.46,1.14,1.18,0.96,1.21,1.18,1.2,1.18,1.2,1.33,1.01,1.31,1.16,1.28,1.21,1.42,1.29,1.04,1.28,1.12,1.2,1.23,1.39,1.26,1.03,1.27,1.18,1.11,1.31,1.46,1.15,1.23,1.21
uj5u.com熱心網友回復:
一種技巧是用一分錢作業,給每個人一個開始,然后隨機挑選隨后的人給額外的一分錢,直到你用完一分錢。這應該給出 的平均值1.20和標準偏差1。代碼比較簡單:
const stats = (ns, Σ = ns .reduce ((a, b) => a b, 0), μ = Σ / ns.length, σ2 = ns .map (n => (n - μ) ** 2) .reduce ((a, b) => a b), σ = Math .sqrt (σ2)) => ({sum: Math .round(Σ), mean: μ, stdDev: σ, min: Math .min (...ns), max: Math .max (...ns)})
const randomDist = (buckets, total, {factor = 100, min = 1} = {}) =>
Array (total * factor - buckets * min) .fill (1) .reduce (
(res, _) => {res [Math.floor (Math.random() * buckets)] = 1 ; return res},
Array (buckets) .fill (min)
) .map (n => n / factor)
const res = randomDist (100, 120)
console .log (stats (res))
console .log (res)
.as-console-wrapper {max-height: 100% !important; top: 0}
我們接受要包含的桶數和總金額。我們還可以選擇接受用于轉換為最小步長和每個人獲得的最小值的因子。(該stats功能僅用于報告目的。)
使用這種技術,價差可能很小。雖然理論上一個人有可能獲得$.01或$119.01,但這種可能性非常小。我們可以通過隨機選擇在每一步向一個人添加多少(而不是只使用一分錢)來改變這一點。我沒有很強的統計學背景來證明這種機制是合理的,但它似乎相對強大。它將需要另一個可選引數,我稱之為block,這是我們將分配的最大塊大小。它看起來像這樣:
const {floor, exp, random, log, min, max, sqrt} = Math
const stats = (ns, Σ = ns .reduce ((a, b) => a b, 0), μ = Σ / ns.length, σ2 = ns .map (n => (n - μ) ** 2) .reduce ((a, b) => a b), σ = sqrt (σ2)) => ({mean: μ, stdDev: σ, min: min (...ns), max: max (...ns)})
const randomDist = (buckets, total, {factor = 100, minimum = 1, block = 100} = {}) => {
const res = Array (buckets) .fill (minimum)
let used = total * factor - buckets * minimum
while (used > 0) {
const bucket = floor (random () * buckets)
const amount = 1 floor (exp (random () * log ((min (used, block)))))
used -= amount
res [bucket] = amount
}
return res .map (r => r / factor)
}
const res1 = randomDist (100, 120)
console .log (stats (res1))
console .log (res1)
const res2 = randomDist (100, 120, {block: 500})
console .log (stats (res2))
console .log (res2)
.as-console-wrapper {max-height: 100% !important; top: 0}
請注意,當我們從 的默認塊大小切換100到 時500,我們會從統計資料中轉到
{mean: 1.2, stdDev: 7.48581986157829, min: 0.03, max: 3.52}
對這樣的人:
{mean: 1.2, stdDev: 17.75106194006432, min: 0.01, max: 10.39}
如果我們繼續下去10,它可能看起來像
{mean: 1.2, stdDev: 2.707932606251492, min: 0.67, max: 2.13}
您可以使用該引數,直到它的分布看起來像您想要的那樣。(如果您將其設定為1,它將具有與第一個代碼段相同的行為。)
uj5u.com熱心網友回復:
目標分布應該是什么?
MBo 給出了 AFAIK 泊松分布(原始方法是在 1 和 11999 的范圍之間隨機放置 99 個分頻器)。另一種方法是先將金額平均分配,然后每兩個成員通過將 0 到 1.19 美元之間的隨機金額從一個人轉移到另一個人來重新分配財富。
重復幾次,如果最大數量只是期望值的 2 倍還不夠。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/383942.html
標籤:javascript 算法 数学 随机的 数字
上一篇:bash腳本中的“預期運算元”
下一篇:最左前綴有手就會,那索引下推呢?
