2012-01-16 6 views
1

私は素数候補ごとに反復したい素数除数のシーケンスを持っています。私はGetEnumerator()MoveNext()とCurrentを使用します。列挙子を最初からやり直すことはできません。私は、コンパイルされたReset()を試みましたが、実装されていないランタイムエラーが発生します。F#:列挙子を再初期化したい

私はF#2.0インタラクティブ4.0.40219.1

任意の提案を構築し使用していますか?問題を明確にするために

よろしく、 ダグ


:各最有力候補についてNI(約の平方根のNまで)プライム除数シーケンスを通して反復し、完全要因たいNまたはそれが素数であるかどうかを判断。 GetEnumerator、MoveNextを使用して、現在のアプローチは最初のプライム候補には機能しますが、2番目のプライム候補では、最初から除数シーケンスを繰り返したいと思っています。これを行う唯一の方法は、新しいイテレータ(多数のプライム候補に対しては厄介です)を作成するか、新しいプライムシーケンス(私がしたくない)を作成することです。

"divisors in seqPrimes"のようなものを使用することの提案は、停止する前にすべての除数を使い果たしているように見えますが、素数の除数が分割するとすぐに停止したいと考えています。

上記の記述に私の論理に誤りがある場合は、私にお知らせください。

私はSeq.cacheを調査しましたが、これは私のために働いていました。結果のコードは次のとおりです。あなたは列挙子をリセットするために、あなたの試みの原因は素数のあなたのシーケンスを再生する高コストであることを意味する場合は、cachingあなたの順序を考慮することができる


// Recursive isprime function (modified from MSDN) 
let isPrime n = 
    let rec check i = 
     i > n/2 || (n % i <> 0 && check (i + 2)) 
    if n = 2 then true 
    elif (n%2) = 0 then false 
    else check 3 

let seqPrimes = seq { for n in 2 .. 100000 do if isPrime n then yield n } 

// Cache the sequence to avoid recomputing the sequence elements. 
let cachedSeq = Seq.cache seqPrimes 


// find the divisors of n (or determine prime) using the seqEnum enumerator 
let rec testPrime n (seqEnum:System.Collections.Generic.IEnumerator<int>) = 
    if n = 1 then printfn "completely factored" 
    else 
    let nref = ref n 
    if seqEnum.MoveNext() then 
     let divisor = seqEnum.Current 
     //printfn "trial divisor %A" divisor 
     if divisor*divisor > n then printfn "prime %A" !nref 
     else 
     while ((!nref % divisor) = 0) do 
      printfn "divisor %A" divisor 
      nref := !nref/divisor 
     testPrime !nref seqEnum 

// test 
for x = 1000000 to 1000010 do 
    printfn "\ndivisors of %d = " x 
    let seqEnum = cachedSeq.GetEnumerator() 
    testPrime x seqEnum 
    seqEnum.Dispose() // not needed 
+2

'for x in y'構文を使用するだけで、実際にはIEnumeratorでメンバーを明示的に呼び出す必要はほとんどありません。もしあなたが必要ならば;新しい列挙子を作成するだけです。あなたのコードを投稿することは、私たちがより良い選択肢を見つけることができると思うので役に立ちます。 – vcsjones

+1

エラーを具体的に示す例がありますか? – pad

+0

Seq.cacheを使用しようとしましたか? – Huusom

答えて

3

。あなたのシーケンスを使用するこの方法はF#にとって慣用的です。私はthis contextから取った次のスニペットにあなたを参照してください。これを行う方法をお見せするために:

let rec primes = 
    Seq.cache <| seq { yield 2; yield! Seq.unfold nextPrime 3 } 
and nextPrime n = 
    if isPrime n then Some(n, n + 2) else nextPrime(n + 2) 
and isPrime n = 
    if n >= 2 then 
     primes 
     |> Seq.tryFind (fun x -> n % x = 0 || x * x > n) 
     |> fun x -> x.Value * x.Value > n 
    else false 

あなたはここで再列挙のペナルティは無視でき得ることを確認するには、このスニペットでプレイしてもよいです。

Reset()の方法がIEnumeratorであると言えば、それは現在のF#では実装されていない、つまりSystem.NotSupportedExceptionをスローします。正当な理由については、MSDN referenceを参照してください。

ADDITION:あなたは以下を示唆してきたテストでそれをテストするために :私のラップトップのテスト実行で

for x in [1000000..1000010] do 
    printfn "\ndivisors of %d" x 
    primes 
    |> Seq.takeWhile ((>) (int(sqrt(float x)))) 
    |> Seq.iter (fun n -> if x%n = 0 then printf "%d " n) 

は単なる3msのをとります。

+0

コメントありがとうございます。列挙子をリセットする(シーケンスの先頭から開始する)ので、新しい列挙子を作成するか(多数の素数候補をテストするのが難しいようです)、新しいシーケンスを作成する必要があります。やってみたいです)。 – DougT

+0

「あなたの質問に答える」を使用して送信しましたが、まだ表示されていません。 – DougT

+1

@DougT:そうです。列挙子をリセットすることは、新しい列挙子を作成することと同じです。後者はF#で普通かつ慣用的で​​す。キャッシュされたシーケンスを使用すると、この一連の処理にパフォーマンスのペナルティは発生しません。上のコードで 'fsi'で遊んで自分自身で見ることができます。 –

関連する問題