4

特定の増分で 2 つの値を補間する小さな関数を作成しようとしています。

[ 1.0 .. 0.5 .. 20.0 ]

コンパイラは、これは推奨されていないことを示しており、int を使用してから float にキャストすることを提案しています。しかし、分数のインクリメントがある場合、これは少し長すぎるようです-開始値と終了値をインクリメントで割ってから、後で再度倍数にする必要がありますか? (うん!)。

シーケンス内包表記を使用してこれを行う方法についてどこかで見たことがありますが、その方法を思い出せません。

助けてください。

4

6 に答える 6

5

興味深いことに、float 範囲はもはや廃止されていないようです。そして、最近、float 範囲で現れる固有の問題について話している質問を見たのを覚えています (申し訳ありませんが、追跡できませんでした)。

> let xl = [0.2 .. 0.1 .. 3.0];;

val xl : float list =
  [0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6;
   1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9]

decimalこの種の丸めの問題がはるかに少ない型で範囲を使用できることを指摘したかっただけです。

> [0.2m .. 0.1m .. 3.0m];;
val it : decimal list =
  [0.2M; 0.3M; 0.4M; 0.5M; 0.6M; 0.7M; 0.8M; 0.9M; 1.0M; 1.1M; 1.2M; 1.3M;
   1.4M; 1.5M; 1.6M; 1.7M; 1.8M; 1.9M; 2.0M; 2.1M; 2.2M; 2.3M; 2.4M; 2.5M;
   2.6M; 2.7M; 2.8M; 2.9M; 3.0M]

最後にフロートが本当に必要な場合は、次のようなことができます

> {0.2m .. 0.1m .. 3.0m} |> Seq.map float |> Seq.toList;;
val it : float list =
  [0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6;
   1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9; 3.0]
于 2011-04-16T23:10:29.863 に答える
2

Jon と他の人が指摘したように、浮動小数点の範囲式は数値的に堅牢ではありません。たとえば、[0.0 .. 0.1 .. 0.3]等しい[0.0 .. 0.1 .. 0.2]。範囲式で Decimal または Int 型を使用する方がよいでしょう。

フロートの場合、私はこの関数を使用します。最初に最小のフロート ステップで合計範囲を 3 倍に増やします。このアルゴリズムが現在非常に堅牢であるかどうかはわかりません。しかし、ストップ値が Seq に含まれていることを確認するだけで十分です。

let floatrange start step stop =
    if step = 0.0 then  failwith "stepsize cannot be zero"
    let range = stop - start 
                |> BitConverter.DoubleToInt64Bits 
                |> (+) 3L 
                |> BitConverter.Int64BitsToDouble
    let steps = range/step
    if steps < 0.0 then failwith "stop value cannot be reached"
    let rec frange (start, i, steps) =
        seq { if i <= steps then 
                yield start + i*step
                yield! frange (start, (i + 1.0), steps) }
    frange (start, 0.0, steps)
于 2013-06-23T16:06:20.303 に答える
0

範囲を生成するための比較的単純な関数を作成することもできます。

let rec frange(from:float, by:float, tof:float) =
   seq { if (from < tof) then 
            yield from
            yield! frange(from + by, tof) }

これを使用すると、次のように書くことができます。

frange(1.0, 0.5, 20.0)
于 2008-12-18T11:50:32.450 に答える
0

Tomas Petricek の回答の更新版。コンパイルされ、減少する範囲で機能します (および測定単位で機能します): (ただし、見栄えはよくありません)

let rec frange(from:float<'a>, by:float<'a>, tof:float<'a>) = 
   // (extra ' here for formatting)
   seq { 
        yield from
        if (float by > 0.) then
            if (from + by <= tof) then yield! frange(from + by, by, tof) 
        else   
            if (from + by >= tof) then yield! frange(from + by, by, tof) 
       }

#r "FSharp.Powerpack"
open Math.SI 
frange(1.0<m>, -0.5<m>, -2.1<m>)

更新これが新しいものなのか、それとも常に可能だったのかはわかりませんが、( here )、この-より単純な-構文も可能であることを発見しました:

let dl = 9.5 / 11.
let min = 21.5 + dl
let max = 40.5 - dl

let a = [ for z in min .. dl .. max -> z ]
let b = a.Length

(注意してください、この特定の例には落とし穴があります:)

于 2009-01-12T13:48:57.043 に答える
0

次のシーケンス式を試してください

seq { 2 .. 40 } |> Seq.map (fun x -> (float x) / 2.0)
于 2008-12-18T07:25:06.870 に答える