英文:
Theoretical analysis of the algorithm that returns true or false, given a probability
问题
要实现一个以概率 n/m
返回 true
,以概率 (m-n)/m
返回 false
的方法。例如,我希望以 7/10000 的概率得到 true
。
为了实现这个目标,首先从函数 getRandomIntUnderN
中获得一个小于 10000 的随机整数 n
。然后,判断 n
是否小于 (7+1),如果是,则返回 true
,否则返回 false
。
以下是你的实现代码:
// 0 is included while n is not
const getRandomIntUnderN = (n) => {
const rn = Math.random() * n
return Math.trunc(rn)
}
// the opportunity of a truthy return value is n/m
const goAtChance = (n, m) => {
return getRandomIntUnderN(m) < n
}
// a opportunity of 7‰ to return true
console.log(goAtChance(7, 10000))
你的问题是:仅仅判断 n
是否小于 (7+1) 是否足够使概率符合预期?
一方面,从1到7的数字在1到10000的范围内不是足够离散分布的,这可能会导致一个使返回真值的概率较低的偏向。
另一方面,由于可以从 getRandomIntUnderN
获得纯随机数字,因此选择哪些数字来确定返回值不会影响概率。可以是 [1,2,3,4,5,6,7],[21,22,23,24,25,26,27],[23,55,3,66,762,92,123] 或任何小于10000的数字。
那么,哪种观点是正确的呢?
从理论上讲,你的方法在大多数情况下会接近所期望的概率,但不是完美的。因为随机数的分布不是完全均匀的,所以可能会有一些偏差。如果需要更精确的概率,可以使用更复杂的随机数生成算法,以确保更接近预期的概率。
英文:
I want to implement a method that returns true
with a probability of n/m
and returns false
with a probability of (m-n)/m
.
For example, I want to get true
with a probability of 7/10000.
To achieve this, I first get a random integer n
that is under 10000 from the function getRandomIntUnderN
. Then, I judge whether n
is smaller than (7+1), if it is, I return true
, false
if not.
I have an implementation below:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
// 0 is included while n is not
const getRandomIntUnderN = (n) => {
const rn = Math.random() * n
return Math.trunc(rn)
}
// the opportunity of a truthy return value is n/m
const goAtChance = (n, m) => {
return getRandomIntUnderN(m) < n
}
// a opportunity of 7‰ to return true
console.log(goAtChance(7, 10000))
<!-- end snippet -->
My question is: is it okay that I just judge whether n
is under (7+1) to make a perfect probability as expected?
On one hand, numbers from 1 to 7 are not distributed discretely enough in the range from 1 to 10000: it seems there will be a bias that makes it unlikely to return a truthy value.
On the other hand, since I can get a purely random number from getRandomIntUnderN
, the chance will not be affected by which numbers I choose to determine the return value. It can be [1,2,3,4,5,6,7], [21,22,23,24,25,26,27], [23,55,3,66,762,92,123] or whatever under 10000.
So, which opinion is right?
答案1
得分: 3
以下是您要翻译的内容:
Then, I judge whether n is smaller than (7+1), if it is, return true, false if not.
这不是您实现的方式。您的代码检查 n 是否小于 7,这是正确的方式。
it seems there will be a bias that makes it unlikely to return a truthy value.
这个陈述来自哪里?当然,您可以测试这个前提...并查看它有多大的可能性。
the chance will not be affected by which numbers did I choose to determine the return value
这是正确的。
如何测试
您可以轻松测试您的实现的分布情况。您可以反复调用函数并记录您得到的结果,然后查看随时间的演变如何。在统计学中,样本的大小越大,您获得的结果就越可靠。
以下是一段代码片段,它会不断执行 goAtChance
函数并记录调用的总次数以及 true
结果的次数。每隔 10 毫秒,页面上的结果会更新,包括 true
数量与总数的比率。如果一切正常,这个比率随着时间的推移应该趋于 0.0007。
const getRandomIntUnderN = (n) => Math.floor(Math.random() * n);
const goAtChance = (n, m) => getRandomIntUnderN(m) < n;
let [outTotal, outHits, outRatio] = document.querySelectorAll("span");
let hits = 0; // 结果为 true 的次数
let total = 0; // 总次数
requestAnimationFrame(function loop() {
let deadline = performance.now() + 10;
do {
hits += goAtChance(7, 10000); // 布尔值会强制转换为 0 或 1
total++;
} while (performance.now() < deadline);
// 显示累积结果
outTotal.textContent = total;
outHits.textContent = hits;
outRatio.textContent = (hits / total).toFixed(8);
requestAnimationFrame(loop); // 允许屏幕更新,然后继续
});
Samples: <span></span><br>
Hits: <span></span><br>
Ratio: <span></span>
希望这些信息对您有帮助。
英文:
> Then, I judge whether n is smaller than (7+1), if it is, return true, false if not.
This is not how you implemented it. Your code checks that n is less than 7, which is the correct way to do it.
> it seems there will be a bias that makes it unlikely to return a truthy value.
Where does that statement come from? Surely you can test this premise... and see how likely it is.
> the chance will not be affected by which numbers did I choose to determine the return value
This is true.
How to test
You can easily test what the distribution is of your implementation. You can call the function repeatedly and keep a record of the results you get, and see how that evolves over time. In statistics you get more reliable results the greater the size of your sample is.
Here is a snippet that keeps executing the goAtChance
function and records the total number of calls and the number of true
results. Every 10 milliseconds the results are updated on the page, including the ratio of the number of true
over the total number. This ratio should over time converge to 0.0007 if all is well.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const getRandomIntUnderN = (n) => Math.floor(Math.random() * n);
const goAtChance = (n, m) => getRandomIntUnderN(m) < n;
let [outTotal, outHits, outRatio] = document.querySelectorAll("span");
let hits = 0; // Number of results that are true
let total = 0; // Total number of results
requestAnimationFrame(function loop() {
let deadline = performance.now() + 10;
do {
hits += goAtChance(7, 10000); // boolean coerces to 0 or 1
total++;
} while (performance.now() < deadline);
// Show the accumulated results
outTotal.textContent = total;
outHits.textContent = hits;
outRatio.textContent = (hits / total).toFixed(8);
requestAnimationFrame(loop); // Allow screen to update and then continue
});
<!-- language: lang-html -->
Samples: <span></span><br>
Hits: <span></span><br>
Ratio: <span></span>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论