4

範囲内で double を生成する関数があります。

let gen_doublein = 
    fun mx mn -> Arb.generate<float> |> Gen.suchThat ( (>) mx ) |> Gen.suchThat ( (<) mn )

次に、これらのうちの 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|] }

置いた:

static member arb_params = Arb.fromGen  gen_params

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

次に、配列ジェネレーター「arrayOfLength」を使用します。

Check.Quick (Prop.forAll (arrayOfLength 2) (fcheck f2))

ただし、期待どおりに動作します。

Check.Quick (Prop.forAll (Generators.arb_params) (fcheck f2))

計算を開始しただけで、戻ってきません。f# の達人、助けてください。

4

3 に答える 3

3

float私はこれを試しませんでしたが、ジェネレーターがランダムに値を作成し、指定した述語 (範囲) と一致するかどうかをチェックすることが問題だと思います。これは、(ランダムに) 一致する float を生成する前に、多数の 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)) }

編集すでに問題を解決しているようです。私が投稿した解決策は、より狭い範囲 (ランダム ジェネレーターが十分な一致値をすぐに生成しない場合) にも関連する可能性があると思います。

于 2012-03-20T16:09:25.323 に答える
2

問題は、パラメーターが間違った方法であったことです。Tomas の提案は良いものであり、それを実装するためのヘルパー関数がいくつかあります。

// Another id function
let fd (d:double) = d
// Check that it is in bounds
let mn=1.0
let mx=5.0
let fdcheck d = (fd d <= mx) && (fd d >= mn)
// Run the check with the numbers generated within the bounds
Check.Quick (Prop.forAll (Arb.fromGen (Gen.map (fun x->
                                                match x with 
                                                | _ when Double.IsNaN x -> (mn+mx)/2.0
                                                | _ when x>  1e+17 ->mx
                                                | _ when x< -1e17 ->mn
                                                | _ -> mn + (mx-mn)*(sin x+1.0)/2.0
                                            ) Arb.generate<double>
                                    )
                       ) fdcheck
         )

ここに、パラメーターが正しく生成された場合にテストに合格する関数があります。整数に関するトーマスのアイデアがうまくいくかどうかはわかりません。なぜなら、多くの小さな整数が生成され、倍精度はドメインをあまり探索しないと思うからです - しかし、FSCheck を知っている誰かが私たちを啓発するかもしれません

于 2012-03-21T11:51:22.687 に答える
2

@b1g3ar5 のサンプルをこのように書き直した

let mapRangeNormal (min : float<_>, max : float<_>) x =
    match x with
    | _ when Double.IsNaN x -> (min + max) / 2.0
    | _ when Double.IsPositiveInfinity x -> max
    | _ when Double.IsNegativeInfinity x -> min
    | _ -> min + (max - min) * (sin x + 1.0) / 2.0

let mapRangeUniform (min : float<_>, max : float<_>) x =
    match x with
    | _ when Double.IsNaN x -> (min + max) / 2.0
    | _ when Double.IsPositiveInfinity x -> max
    | _ when Double.IsNegativeInfinity x -> min
    | _ when x < 0.0 ->
           let newRange = max - min
           min - x * (newRange / Double.MaxValue) - newRange / 2.0
    | _ -> let newRange = max - min
           min + x * (newRange / Double.MaxValue) + newRange / 2.0
于 2016-09-14T12:28:48.363 に答える