【发布时间】:2017-05-08 04:52:34
【问题描述】:
我在使用 ScalaCheck 的 Gen.pic 时观察到以下意外行为,这(对我而言)表明它的选择不是很随机,尽管 its documentation 这么说:
/** A generator that picks a given number of elements from a list, randomly */
设置后,我按顺序运行了以下三个小程序(在 2 天内,在不同的时间,可能很重要)
implicit override val generatorDrivenConfig = PropertyCheckConfig(
maxSize = 1000,
minSize = 1000,
minSuccessful = 1000)
获得合适的样本量。
计划 #1
val set = Set(1,2,3,4,5,6,7,8,9,10,
11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50)
// Thanks to @Jubobs for the solution
// See: http://stackoverflow.com/a/43825913/4169924
val g = Gen.pick(3, set).map { _.toList }
forAll (g) { s => println(s) }
在 2 次不同运行生成的 3000 个数字中,我得到了惊人的相似,并且非常非随机分布(数字是四舍五入的,仅列出前 5 个,至于从这里开始的所有列表):
- 数字:运行 #1 中的频率,运行 #2 中的频率
- 15:33%、33%
- 47:22%、22%
- 4:15%、16%
- 19:10%、10%
- 30:6%、6%
(免责声明:除了this way,我找不到如何在此处创建表格)
方案 2
val list: List[Int] = List.range(1, 50)
val g = Gen.pick(3, list)
forAll (g) { s => println(s) }
在使用List 的情况下,数字似乎会“卡在”范围的末尾(在两次运行的情况下为 3x1000 个数字):
- 49:33%、33%
- 48:22%、22%
- 47:14%、14%
- 46:10%、10%
- 45:6%、6%
有趣的是,频率与程序 1 的情况几乎相同。
备注:我对列表重复运行多达 10 次,并且经历了完全相同的分布,差异为 +/- 1%,只是不想在此处列出所有数字奇怪的“表格”格式。
方案 3
为了增加趣味性,我运行了第三个小 sn-p,从 List(程序 2)创建了 Set(程序 1):
val set: Set[Int] = List.range(1, 50).toSet
val g = Gen.pick(3, set).map { _.toList }
forAll (g) { s => println(s) }
现在数字与程序 2 相同(List 获胜!),尽管频率(同样,2 次运行中的 3*1000 数字)在最后略有不同:
- 49:33%、33%
- 48:23%、22%
- 47:16%、15%
- 46:9%、10%
- 45:7%、6%
问题
即使样本量不足以(因为它永远都不够)告诉真实随机性,我不禁质疑Gen.pick声称的随机性(就使用它而言开箱即用,我可能需要设置一些种子让它随机“更多”工作),因为数字“卡住”了,而且频率几乎相同。
在查看 Gen.pick's source code 时,在第 #672 行使用了某个 seed0:
def pick[T](n: Int, l: Iterable[T]): Gen[Seq[T]] = {
if (n > l.size || n < 0) throw new IllegalArgumentException(s"invalid choice: $n")
else if (n == 0) Gen.const(Nil)
else gen { (p, seed0) =>
// ...
我在其他任何地方都找不到定义(在Gen.scala source code 或scala.util.Random 文档中),但我有预感它可能与观察到的行为有关。
这是Gen.pick 的预期行为吗?如果是这样,我怎样才能获得“更多”的随机挑选?
【问题讨论】:
-
Bugfoot,不确定你是否还在乎,但我认为@ashawley 的诊断是错误的,这实际上只是一个错误。有关详细信息,请参阅我的答案
-
您的回复现在被接受为答案,感谢您加倍努力。
标签: scala random scalacheck