【问题标题】:Check probability检查概率
【发布时间】:2018-06-01 14:58:26
【问题描述】:

我有一个 C++ 应用程序,它基于某种算法为某些操作选择 5 个实体之一。

我正在编写一个单元测试以确保所有 5 个都有相同的概率被选中。我正在运行 1000 次测试并获得结果,每个人都被选择了多少次。这是结果示例 202、192、224、195、187

如果计数接近 200,添加检查是否正确?

我正在使用 boost 测试库。

【问题讨论】:

  • 为您认为“接近 200”设置一个边界。结果减去200,得到绝对值,看看是否在边界内。
  • @DeiDei 所以假设 10% 然后 200 - 20
  • 更通用的解决方案是实际测量方差:en.wikipedia.org/wiki/Variance
  • 这是一道统计题,而不是编程题。考虑改为在 math.stackexchange.com 上询问。
  • 如果某个结果出现的概率不等于 1,那么也有一个非零概率它不会出现。因此,即使算法按要求运行,您设计的任何单元测试有时也会失败。与其使用分布的单元测试,不如进行分析以确定导致算法表现出所需统计行为的输入条件集,并确认算法仅提供此类输入。然后,单元测试可能是确认算法始终提供合适输入的一种选择。

标签: c++ unit-testing boost


【解决方案1】:

一个快速的经验法则是,在 Y% 的 X 样本中,您通常会得到 Y%*X +/- sqrt(X)。

这是第二个标准偏差的近似值,因此您在 +/- sqrt(X) 元素内的几率大约为 95%。

您可以将 1.5*sqrt(X) 用于 3 个标准差的近似值,这应该发生在 99.7% 的时间。

您还可以备份并使用精美的统计数据来获得更准确的答案。

因此,对于 1000 个样本,对于 sqrt(X) 而言是 +/- 31,对于 1.6*sqrt(X) 而言是 +/- 47。

这个 sqrt 规则生成一个比它需要的更宽松的界限。

要推导出它,首先要考虑一个 Y 机会硬币的 Var 为 (1-Y)(Y) 的事实。请注意,此多项式在 Y=0.5 时最大。

所以 Var(X 个硬币与概率 Y)

SD(X 个硬币,概率为 Y) 为

95% 区间为 1.96 SD; 2大于那个。所以 1.96 SD

适当的推导会考虑到我们希望学生 T 分布,因为我们是从 XY 的样本中估计 Y,而不是从 Y 中估计 XY,但考虑到慷慨的捏造因素。

查看chart on wikipedia,如果您每天进行 1 次测试,则可能会失败:

  • 1 sigma:2 次/周
  • 2 sigma:每 3 周
  • 3 sigma:每年
  • 4 sigma:每 43 年(一生两次)
  • 5 sigma:每 4776 年(有记载的历史记录一次)
  • 6 sigma:每百万年(在人类生命周期中一次)

由于 sqrt(X) 是 2 sigma 的近似值,因此 2*sqrt(X) 会在每个生命周期中导致 2 次虚假单元测试失败,而 3*sqrt(X) 在实践中永远不会失败。

请注意,如果您每天重复此测试一百万次,您可能需要更多的 sigma。

【讨论】:

  • 由于这个问题是在单元测试的上下文中,95% 的置信度意味着即使生成它的代码没有错误,单元测试仍有 5% 的时间会失败。如果您必须测试多个分布,则问题会更加复杂。在我看来,单元测试不是检查分布正确性的合适场所。
  • @FrançoisAndrieux 提升 sigma,它达到了虚假故障的可能性低于宇宙射线翻转表明故障发生的位。
  • 如上所述,我将为其他实现确定性分布的方法添加单元测试。考虑将概率测试添加为集成测试而不是单元测试。
  • @Yakk-AdamNevraumont 如果你做得足够好,即使你的发行版很糟糕,你的测试也会通过。
【解决方案2】:

您想要实现的是“验证”:您想要检查您实施的系统是否符合您的需求。在您的情况下,这意味着您要检查算法是否以正确的分布提供数据。

或者,从不同的角度来看同一件事:在执行时,您并没有检查是否有错误 - 即使您的代码没有错误,它也可能根本无法执行您想要的操作。

这不是单元测试适用的测试类型。单元测试用于“验证”,旨在发现代码中的错误 - 它不是为了确定您选择的算法是否正确。打个比方:通过单元测试,您可以检查您是否正确实施了快速排序,但这不是检查您是否应该实施堆排序。

这并不是说您的测试目标没有意义——只是说明您正在实施的测试不是通常意义上的单元测试。此外,您的测试缺少单元测试通常应该具备的一项重要属性:确定性。

也就是说,您仍然可以使用所谓的单元测试框架之一来实现您的测试,因为这些框架绝不限于使用它们进行单元测试。我只是建议不要使用您的单元测试来实施和运行这些测试。以相同的频率运行它们也没有什么意义:一旦你知道你选择了正确的算法,你就可以编写一些(真实的)单元测试来查找错误/回归。您可以定期运行这些单元测试,但不必重新运行验证测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    相关资源
    最近更新 更多