【发布时间】:2012-11-11 10:47:36
【问题描述】:
在一次采访中,我得到了以下问题,最初使用笔/纸解决,然后通过程序验证结果。
问题如下:
共有 A、B 和 C 三个人。每个人能够分别以 6/7、4/5 和 3/4 的概率击中目标。如果他们每个人都开一枪,那么他们中恰好有两个人会击中目标的概率是多少?
答案是:
P(...) = P(A)*P(B)*(1-P(C)) +
P(B)*P(C)*(1-P(A)) +
P(C)*P(A)*(1-P(B))
= 27.0/70.0
= 38.57142857142857142857142857142857142857....%
以下是我对问题的解决方案:
#include <cstdio>
#include <cctype>
#include <ctime>
#include <random>
int main()
{
std::mt19937 engine(time(0));
engine.discard(10000000);
std::uniform_real_distribution<double> uniform_real(0.0,1.0);
double prA = (6.0 / 7.0);
double prB = (4.0 / 5.0);
double prC = (3.0 / 4.0);
std::size_t trails = 4000000000;
std::size_t total_success = 0;
for (std::size_t i = 0; i < trails; ++i)
{
int current_success = 0;
if (uniform_real(engine) < prA) ++current_success;
if (uniform_real(engine) < prB) ++current_success;
if (uniform_real(engine) < prC) ++current_success;
if (current_success == 2)
++total_success;
double prob = (total_success * 1.0) / (i+1);
if ((i % 1000000) == 0)
{
printf("%05d Pr(...) = %12.10f error:%15.13f\n",
i,
prob,
std::abs((27.0/70.0) - prob));
}
}
return 0;
}
问题如下,无论我运行了多少次试验,概率都在大约 0.3857002101 左右持平。代码有问题吗?
面试官说,无论种子如何,在 100 万次试验中让结果收敛到小数点后 9 位精度是微不足道的。
关于错误在我的代码中的任何想法?
更新 1: 我已经使用以下生成器尝试了上述代码,它们似乎都在大约同一时间大致试验 10 ^ 9。
- std::mt19937_64
- std::ranlux48_base
- std::minstd_rand0
更新 2: 考虑到这个问题,我走上了下面的路。比率 27/70 由 27 和 70 组成,它们都是互质的,并且 4x10^9 下的 70 因子大约是 57x10^6 或所有数字的 1.4%。因此,从 [0,4x10^9] 之间随机选择的两个数字中获得 27/70 的“精确”比率的概率大约为 1.4%(因为在 4x10^9 内有更多的 27 因子) - 所以得到确切的比率非常低,无论试验次数如何,这个数字都是恒定的。
现在,如果在哪里谈论厚界限 - 即:在 70 +/5 的因子范围内的数字,这会增加在 [0,4x10^9] 范围内随机选择一对数字的概率将在指定/相关公差范围内给出大约 14% 的比率,但使用这种技术,与精确值相比,我们可以获得的最佳结果平均约为小数点后 5 位。这种推理方式正确吗?
【问题讨论】:
-
DV 标题不准确(你拒绝接受我的编辑)。它正在收敛,只是没有达到你想要的值。如果你问为什么它会收敛到 0.3857002101,这应该因为过于本地化而被关闭。如果您提出关于精度误差来自何处的问题,这是可以接受的。
-
mt19937 几乎是最快和最便宜的随机数引擎。您应该期望它不会产生完全均匀的分布,在应用二项式概率后,会产生一个小的偏差。你试过其他引擎吗?
-
@MikaelPersson:感谢您的建议,我尝试了以下方法:std::mt19937_64、std::ranlux48_base 和 minstd_rand0,它们似乎都给出了相同的结果。我会用我尝试过的生成器更新问题,希望 djechlin 的傀儡账户不会再对我投反对票了 :)
-
+1 有趣。就其价值而言,根据maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/cfCALC.html,您的结果与任何其他有理数都不是特别接近
-
根据经验,蒙特卡洛积分(这里的这个问题可以看作是一个非常简单的例子)的精度通常会随着
1/sqrt(N)而降低,其中N是试验(参见例如 en.wikipedia.org/wiki/Monte_Carlo_integration ),因此您需要 O(10^18) 次试验以获得 10^-9 的精度。当然除非你使用解析公式,在这种情况下你在一次迭代后就完成了......
标签: java c++ algorithm math simulation