1

私は scala を学んで楽しんでいます。これは非常に強力な言語です。プロジェクトオイラーから、オイラー#2の問題を解決するためにこのプログラムを書きました。400 万未満の偶数フィボナッチ数の合計を見つけることです (これを max# と呼びます)。

最初に takeWhile を使用し、次にフィルターを使用しました。

fib().takeWhile(_ < n).filter(_ % 2 == 0).sum

次に、順序を変更して、takeWhile の前にフィルターを使用することにしました。

fib().filter(_ % 2 == 0).takeWhile(_ < n).sum

これは、max# を増やしたときにパフォーマンスに違いがあるかどうかを確認するために行いました。この入力番号 (4000000000000001237) を使用して 2 つの異なる結果が得られるまで、結果は予想どおり正確であり、パフォーマンスはほぼ同じでした。結果は次のとおりです。

 $ scala com.ms.E2_1 4000000000000001237

   takeWhile 1st    => 3770056902373173214
   filter 1st   => -8573983172444283806

takeWhileの前にフィルターを使用すると、このエラーが発生する理由を誰か説明してもらえますか? ありがとうございました。

object E2_1 {

 def fib(a: Long = 0, b: Long = 1): Stream[Long] = {
  a #:: fib(b, a + b)
 }

 def main(args: Array[String]): Unit = {
   if (args.length == 1) { 
     val n = args(0).toLong     
     println("takeWhile 1st \t=> " + fib().takeWhile(_ < n).filter(_ % 2 == 0).sum)     
     println("filter 1st \t=> " + fib().filter(_ % 2 == 0).takeWhile(_ < n).sum)
  } else {
    println("missing args")
  }
 }
}
4

1 に答える 1

2

関数の順序に応じて、オーバーフローが動作に異なる影響を与える理由は次のとおりです。

scala> fib().takeWhile(_ > -1).toList.reverse.take(2)
res0: List[Long] = List(7540113804746346429, 4660046610375530309)

つまり、オーバーフローが始まる前に計算された最後の数値は、ターゲットよりも大きく、n奇数です

最初に適用するtakeWhileと、結果のストリームはこれらの番号のいずれかを生成します。数値が より大きいnため、結果がオーバーフローに達する前に生産が停止します。

最初に申請するfilterと、これらの奇数は破棄されます。オーバーフローのため、生成される次の偶数は負になる可能性があり、したがって より小さいnため、述語をtakeWhile!に渡します。ストリームは、結果が再び肯定的になり、より大きな数nが生成されるまで続行されます。

于 2013-05-01T10:12:31.080 に答える