使用 FSCheck 生成器

b1g*_*ar5 5 f# fscheck

我有一个函数可以生成一定范围内的双精度数:

let gen_doublein = 
    fun mx mn -> Arb.generate<float> |> Gen.suchThat ( (>) mx ) |> Gen.suchThat ( (<) mn )
Run Code Online (Sandbox Code Playgroud)

然后是一个函数来生成其中 2 个数组:

let gen_params:Gen<double array> = 
    gen { let! x = gen_doublein 0.0 20000.0
          let! y = gen_doublein 0.0 2000.0
          return [| x;y|] }
Run Code Online (Sandbox Code Playgroud)

我放:

static member arb_params = Arb.fromGen  gen_params
Run Code Online (Sandbox Code Playgroud)

在 Generator 类中并注册它。一切看起来都不错。为了测试这是否一切正常,我有:

let f2 (xs:double array) :double= exp (-2.0*xs.[0]) + xs.[1]*exp (-2.0*xs.[0])
let fcheck fn xs = fn xs > 0.0
Run Code Online (Sandbox Code Playgroud)

然后使用数组生成器“arrayOfLength”:

Check.Quick (Prop.forAll (arrayOfLength 2) (fcheck f2))
Run Code Online (Sandbox Code Playgroud)

但是,按预期工作:

Check.Quick (Prop.forAll (Generators.arb_params) (fcheck f2))
Run Code Online (Sandbox Code Playgroud)

刚开始做一些计算就再也没有回来。f# 大师请帮忙。

Tom*_*cek 4

我没有尝试这个,但我认为问题是生成器float随机创建值,然后检查它们是否与您指定的谓词(范围)匹配。这意味着它必须先生成大量浮点数,然后才能(随机)生成匹配的浮点数。

float通过生成[0 .. 1] 范围内的值
,然后重新调整它们以匹配您需要的范围,可以更轻松地生成指定范围内的值。

我对 FsCheck 不太熟悉,所以我不知道是否有 [0 .. 1] 浮点范围的生成器,但您可以从生成整数并将其转换为浮点数开始:

let gen_doublein mx mn = gen {
   let! n = Arb.generate<int>
   let f = float n / float Int32.MaxValue 
   return mx + (f * (mn - mx)) }
Run Code Online (Sandbox Code Playgroud)

编辑我看到你已经解决了问题。我认为我发布的解决方案可能仍然适用于较小的范围(随机生成器不能很快产生足够的匹配值)。