作成時の中間値きます。
-
19-09-2019 - |
質問
私を学習しようとしているF#んを訪問 プロジェクトオイラー と現在、私が取り組んでい 課題3.
の素因の13195 5,7, 13 29.
何が最大の盛り 因子の600851475143?
も発生していると考えること
- 私の最初の優先権を学ぶ良い機能の習慣。
- 第二優先したいと思いますのpcは自由に使用できます。
以内のコードが付いていのこの問題に関する.
let isPrime(n:int64) =
let rec check(i:int64) =
i > n / 2L or (n % i <> 0L && check(i + 1L))
check(2L)
let greatestPrimeFactor(n:int64) =
let nextPrime(prime:int64):int64 =
seq { for i = prime + 1L to System.Int64.MaxValue do if isPrime(i) then yield i }
|> Seq.skipWhile(fun v -> n % v <> 0L)
|> Seq.hd
let rec findNextPrimeFactor(number:int64, prime:int64):int64 =
if number = 1L then prime else
//************* No variable
(fun p -> findNextPrimeFactor(number / p, p))(nextPrime(prime))
//*************
//************* Variable
let p = nextPrime(prime)
findNextPrimeFactor(number / p, p)
//*************
findNextPrimeFactor(n, 2L)
更新
この意していま整理のコードを10倍になります。
module Problem3
module private Internal =
let execute(number:int64):int64 =
let rec isPrime(value:int64, current:int64) =
current > value / 2L or (value % current <> 0L && isPrime(value, current + 1L))
let rec nextPrime(prime:int64):int64 =
if number % prime = 0L && isPrime(prime, 2L) then prime else nextPrime(prime + 1L)
let rec greatestPrimeFactor(current:int64, prime:int64):int64 =
if current = 1L then prime else nextPrime(prime + 1L) |> fun p -> greatestPrimeFactor(current / p, p)
greatestPrimeFactor(number, 2L)
let execute() = Internal.execute(600851475143L)
更新
また全てのみなさんに感謝しますが。この最新バージョンがすべての助言を受信します。
module Problem3
module private Internal =
let largestPrimeFactor number =
let rec isPrime value current =
current > value / 2L || (value % current <> 0L && isPrime value (current + 1L))
let rec nextPrime value =
if number % value = 0L && isPrime value 2L then value else nextPrime (value + 1L)
let rec find current prime =
match current / prime with
| 1L -> prime
| current -> nextPrime (prime + 1L) |> find current
find number (nextPrime 2L)
let execute() = Internal.largestPrimeFactor 600851475143L
解決
プログラミングがしやすくなると自動業務をよりスムーズに行い汗で分かりやすく説明すので絶対に初挑戦しました。
そのようなおサンプルコード:
let rec findNextPrimeFactor(number:int64, prime:int64):int64 =
if number = 1L then prime else
//************* No variable
(fun p -> findNextPrimeFactor(number / p, p))(nextPrime(prime))
//*************
//************* Variable
let p = nextPrime(prime)
findNextPrimeFactor(number / p, p)
//*************
ご no variable
版かもくなります。私のようにバージョンを明示的ましょう。
別の言い方を書き:
nextPrime(prime) |> fun p -> findNextPrimeFactor(number / p, p)
その ok 時に役立つものこのようなものが全体としては少し変わっている。ほとんどの時間を使用していま |>
カレーへの価値 なし する必要が名前を変数"pointfree"風があります。う期待にどのような機能を使用し、可能な場合は、再書きでも利用できるパイプオペレーターなしで明示的に宣言された変数です。例えば:
let rec findNextPrimeFactor number prime =
match number / prime with
| 1L -> prime
| number' -> nextPrime(prime) |> findNextPrimeFactor number'
無名:args)
Ok、ということに見られるように、お isPrime
機能:
let isPrime(n:int64) =
let rec check(i:int64) =
i > n / 2L or (n % i <> 0L && check(i + 1L))
check(2L)
いるところで使用再帰ではなくループには、いくらくらいです。でも、可能な限り、必要旨離れた再帰との折、地図、または高としました。理由とし
その少し読みやすくするために、
不正に書き再帰結でスタックオーバーフロー.例えば、機能しない尾再帰しています。ブロー最大値
n
.
い書き換え isPrime
このように:
let isPrime n = seq { 2L .. n / 2L } |> Seq.exists (fun i -> n % i = 0L) |> not
ほとんどの時間まで抽象しているほうがはるかに明示的なループを、それだけ適用の変容をご入力シーケンスを取得するまで結果:
let maxFactor n =
seq { 2L .. n - 1L } // test inputs
|> Seq.filter isPrime // primes
|> Seq.filter (fun x -> n % x = 0L) // factors
|> Seq.max // result
まな中間変数がこのバージョン。冷!
第二優先したいと思いま 迅速、効率的です。
ほとんどの時間を、F#うのは、僕の比較とC#の速度、またはこれは"十分速く、余裕があります。".ばコードに時間がかかり実行でもご利用中に誤ったデータ構造やアルゴリズムの悪い.具体的な例を挙げれば、コメント この問いに対する.
なので、コードからは"優雅"という感じで簡潔、正しい結果とな依拠しtrickery.残念ながら、そのなのである。開始:
この試作事業部作のシーケンス素数のふるいのEratosthenesうになります。[編集:書いたややナイーブのふるいをしなかった仕事番号をよInt32.MaxValueので、私は削除されたものです。]
読みWikipediaの記事 盛り集計機能, まだポイントの算定についての初の
n
素数と推計の上下の境界nth
盛りです。
[編集:また一部のコードやナイーブの実施にふるいのeratosthenes.でのみ動作のための入力以下のint32.MaxValueのでもないのに適したプロジェクトeuler.]
他のヒント
に関する"良い機能性癖"という良い練習を見つ軽微となる。用利回りにシーケンスが少しくだけでフィルター不必要な型の注釈型推定される言語が難しくリファクタリングのコードが読み出します。うどん落としてい型の注釈がんの発見が難しい。最後に作lambdaる機能だけを使用する値として温度変数を削減可読性
と個人スタイルが好きですからより空間を利用tupled引数が、データの意味があってとめて表示されます。
思書オリジナルのコードのようです。
let isPrime n =
let rec check i =
i > n / 2L || (n % i <> 0L && check (i + 1L))
check 2L
let greatestPrimeFactor n =
let nextPrime prime =
seq {prime + 1L .. System.Int64.MaxValue}
|> Seq.filter isPrime
|> Seq.skipWhile (fun v -> n % v <> 0L)
|> Seq.head
let rec findNextPrimeFactor number prime =
if number = 1L then
prime
else
let p = nextPrime(prime)
findNextPrimeFactor (number / p) p
findNextPrimeFactor n 2L
おの更新をコードに最適なえています。いった人々に対して送られるアルゴリズムのような陰朱答えになります。って試験がF#の"確認"機能尾再帰的です。
の 変数 p、実際には名前の結合ではなく、可変となります。名前との結合が悪いです。し易い。テスタイル nextPrime
が、実際に盛り-試験の各号一度だけのプログラム。
私の解決
let problem3 =
let num = 600851475143L
let rec findMax (n:int64) (i:int64) =
if n=i || n<i then
n
elif n%i=0L then
findMax (n/i) i
else
findMax n (i+1L)
findMax num 2L
については基本的に分numから2,3,4..なと考えたことを盛ります。ない分けて2からnum、そのままで分割で4,8。
この番号、私の溶液を速:
> greatestPrimeFactor 600851475143L;;
Real: 00:00:01.110, CPU: 00:00:00.702, GC gen0: 1, gen1: 1, gen2: 0
val it : int64 = 6857L
>
Real: 00:00:00.001, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
val problem3 : int64 = 6857L
このコードを一時的結合が大きく読みやすくなりました。かの異常を匿名で機能し、その後直ちに適用するときは、その他。または使用しないでくださ仮値ると思うのに慣用的方法が確立されてきていF#うを使用することで (|>)
オペレーターパイプの値を匿名での機能をもたなければならないと思いることかすことはないですね。