Algorithm 学习F#-打印素数
昨天我在业余时间开始看《F#》。我想我会从打印出所有素数到100的标准问题开始。这是我想到的Algorithm 学习F#-打印素数,algorithm,f#,primes,Algorithm,F#,Primes,昨天我在业余时间开始看《F#》。我想我会从打印出所有素数到100的标准问题开始。这是我想到的 #light open System let mutable divisable = false let mutable j = 2 for i = 2 to 100 do j <- 2 while j < i do if i % j = 0 then divisable <- true j <- j + 1 if d
#light
open System
let mutable divisable = false
let mutable j = 2
for i = 2 to 100 do
j <- 2
while j < i do
if i % j = 0 then divisable <- true
j <- j + 1
if divisable = false then Console.WriteLine(i)
divisable <- false
#灯
开放系统
设可变可除=false
设可变j=2
对于i=2到100 do
j简单但低效的建议:
- 创建一个函数来测试单个数字是否为素数
- 创建一个从2到100的数字列表
- 按函数筛选列表
- 使用另一个函数组合结果以打印结果
为了提高效率,你真的想通过检查一个数是否可以被任何较低的素数整除来测试它是否是素数,这需要记忆。可能最好先等到简单版本开始工作:)
如果这还不够提示,请告诉我,我将给出一个完整的示例-虽然可能要到今晚才能实现…使用类似的筛选函数是一个很好的方法。函数式语言在列表中工作得非常好,所以我首先要考虑的是结构
另一方面,函数式语言可以很好地利用函数构造(heh)。对于函数式语言“feel”,我将构建一个筛选函数,然后调用它来打印素数。您甚至可以将其拆分——一个函数构建列表并完成所有工作,另一个函数完成并完成所有打印,将功能整齐地分开
有几个有趣的版本。
还有其他类似语言的著名实现。在OCAML中,它胜过C中的一个。这里是F中的一个简单实现:
此实现不适用于非常大的列表,但它展示了功能解决方案的优雅。您肯定不想从这个示例中学习,但我编写了一个基于消息传递的F#实现:
type 'a seqMsg =
| Die
| Next of AsyncReplyChannel<'a>
type primes() =
let counter(init) =
MailboxProcessor.Start(fun inbox ->
let rec loop n =
async { let! msg = inbox.Receive()
match msg with
| Die -> return ()
| Next(reply) ->
reply.Reply(n)
return! loop(n + 1) }
loop init)
let filter(c : MailboxProcessor<'a seqMsg>, pred) =
MailboxProcessor.Start(fun inbox ->
let rec loop() =
async {
let! msg = inbox.Receive()
match msg with
| Die ->
c.Post(Die)
return()
| Next(reply) ->
let rec filter' n =
if pred n then async { return n }
else
async {let! m = c.AsyncPostAndReply(Next)
return! filter' m }
let! testItem = c.AsyncPostAndReply(Next)
let! filteredItem = filter' testItem
reply.Reply(filteredItem)
return! loop()
}
loop()
)
let processor = MailboxProcessor.Start(fun inbox ->
let rec loop (oldFilter : MailboxProcessor<int seqMsg>) prime =
async {
let! msg = inbox.Receive()
match msg with
| Die ->
oldFilter.Post(Die)
return()
| Next(reply) ->
reply.Reply(prime)
let newFilter = filter(oldFilter, (fun x -> x % prime <> 0))
let! newPrime = oldFilter.AsyncPostAndReply(Next)
return! loop newFilter newPrime
}
loop (counter(3)) 2)
member this.Next() = processor.PostAndReply( (fun reply -> Next(reply)), timeout = 2000)
interface System.IDisposable with
member this.Dispose() = processor.Post(Die)
static member upto max =
[ use p = new primes()
let lastPrime = ref (p.Next())
while !lastPrime <= max do
yield !lastPrime
lastPrime := p.Next() ]
好极了!:) 这里是关于使用递归seq实现素数生成器的
对于想要快速实现的情况,有
另外,如果你想将素数迭代到10^20,你真的想把D.J.Bernstein的primegen移植到F#/OCaml:)在解决同样的问题时,我已经在F#中实现了。它是最有效的现代算法之一
// Create sieve
let initSieve topCandidate =
let result = Array.zeroCreate<bool> (topCandidate + 1)
Array.set result 2 true
Array.set result 3 true
Array.set result 5 true
result
// Remove squares of primes
let removeSquares sieve topCandidate =
let squares =
seq { 7 .. topCandidate}
|> Seq.filter (fun n -> Array.get sieve n)
|> Seq.map (fun n -> n * n)
|> Seq.takeWhile (fun n -> n <= topCandidate)
for n2 in squares do
n2
|> Seq.unfold (fun state -> Some(state, state + n2))
|> Seq.takeWhile (fun x -> x <= topCandidate)
|> Seq.iter (fun x -> Array.set sieve x false)
sieve
// Pick the primes and return as an Array
let pickPrimes sieve =
sieve
|> Array.mapi (fun i t -> if t then Some i else None)
|> Array.choose (fun t -> t)
// Flip solutions of the first equation
let doFirst sieve topCandidate =
let set1 = Set.ofList [1; 13; 17; 29; 37; 41; 49; 53]
let mutable x = 1
let mutable y = 1
let mutable go = true
let mutable x2 = 4 * x * x
while go do
let n = x2 + y*y
if n <= topCandidate then
if Set.contains (n % 60) set1 then
Array.get sieve n |> not |> Array.set sieve n
y <- y + 2
else
y <- 1
x <- x + 1
x2 <- 4 * x * x
if topCandidate < x2 + 1 then
go <- false
// Flip solutions of the second equation
let doSecond sieve topCandidate =
let set2 = Set.ofList [7; 19; 31; 43]
let mutable x = 1
let mutable y = 2
let mutable go = true
let mutable x2 = 3 * x * x
while go do
let n = x2 + y*y
if n <= topCandidate then
if Set.contains (n % 60) set2 then
Array.get sieve n |> not |> Array.set sieve n
y <- y + 2
else
y <- 2
x <- x + 2
x2 <- 3 * x * x
if topCandidate < x2 + 4 then
go <- false
// Flip solutions of the third equation
let doThird sieve topCandidate =
let set3 = Set.ofList [11; 23; 47; 59]
let mutable x = 2
let mutable y = x - 1
let mutable go = true
let mutable x2 = 3 * x * x
while go do
let n = x2 - y*y
if n <= topCandidate && 0 < y then
if Set.contains (n % 60) set3 then
Array.get sieve n |> not |> Array.set sieve n
y <- y - 2
else
x <- x + 1
y <- x - 1
x2 <- 3 * x * x
if topCandidate < x2 - y*y then
go <- false
// Sieve of Atkin
let ListAtkin (topCandidate : int) =
let sieve = initSieve topCandidate
[async { doFirst sieve topCandidate }
async { doSecond sieve topCandidate }
async { doThird sieve topCandidate }]
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
removeSquares sieve topCandidate |> pickPrimes
//创建筛子
让我们选择一个候选者=
让结果=Array.zeroCreate(topCandidate+1)
Array.set结果2 true
Array.set结果3为真
Array.set结果5 true
结果
//去掉素数的平方
让我们去掉方块筛=
让正方形=
seq{7..topCandidate}
|>Seq.filter(乐趣n->Array.get-sieven)
|>序列图(乐趣n->n*n)
|>Seq.takeWhile(乐趣n->n顺序展开(乐趣状态->一些(状态,状态+n2))
|>Seq.takeWhile(fun x->x Seq.iter(fun x->Array.set x false)
筛
//选择素数并作为数组返回
让素数筛选=
筛
|>Array.mapi(乐趣i t->if t然后Some i else None)
|>Array.choose(乐趣t->t)
//第一方程的翻转解
让我们先来看看候选人=
设set1=Set.of列表[1;13;17;29;37;41;49;53]
设可变x=1
设可变y=1
让可变项消失=真
设可变x2=4*x*x
边走边做
设n=x2+y*y
如果n不是|>Array.set n
这是我的两分钱:
let rec primes =
seq {
yield 2
yield! (Seq.unfold (fun i -> Some(i, i + 2)) 3)
|> Seq.filter (fun p ->
primes
|> Seq.takeWhile (fun i -> i * i <= p)
|> Seq.forall (fun i -> p % i <> 0))
}
for i in primes do
printf "%d " i
我将使用Eratosthenes()的筛子来实现它。我可以想象,作为旁注,它对于函数方法非常有用(尽管我对F#一无所知),使用Console.WriteLine
。我建议使用printfn“%I”我
相反,printf更安全,可以推断某些类型。尝试使用折叠重写它。对于已经做了一天的人来说,这里有一些简单的代码:)。可能会传递您的示例,但谢谢lol…很好,但我认为“List.filter(fun x->x%p>0)xs”将比显式列表理解更惯用。请记住,这不是一个真正的筛子。该算法非常慢(与真正的筛子相比,渐进复杂度很差)。让我解释一下区别。埃拉托什尼筛子只标记当前素数的倍数(p
)。这是当前素数步数的倍数。但是,您的代码对所有剩余的数字执行可除性测试,而不仅仅是倍数。随着数字变大,非倍数比倍数多得多,因此您的算法比真实的筛子做了很多额外的工作。这个想法来自这篇很棒的论文:Thanks的信息,非常有趣!这段代码只是在上面的链接中找到的Haskell示例的一个端口。
// Create sieve
let initSieve topCandidate =
let result = Array.zeroCreate<bool> (topCandidate + 1)
Array.set result 2 true
Array.set result 3 true
Array.set result 5 true
result
// Remove squares of primes
let removeSquares sieve topCandidate =
let squares =
seq { 7 .. topCandidate}
|> Seq.filter (fun n -> Array.get sieve n)
|> Seq.map (fun n -> n * n)
|> Seq.takeWhile (fun n -> n <= topCandidate)
for n2 in squares do
n2
|> Seq.unfold (fun state -> Some(state, state + n2))
|> Seq.takeWhile (fun x -> x <= topCandidate)
|> Seq.iter (fun x -> Array.set sieve x false)
sieve
// Pick the primes and return as an Array
let pickPrimes sieve =
sieve
|> Array.mapi (fun i t -> if t then Some i else None)
|> Array.choose (fun t -> t)
// Flip solutions of the first equation
let doFirst sieve topCandidate =
let set1 = Set.ofList [1; 13; 17; 29; 37; 41; 49; 53]
let mutable x = 1
let mutable y = 1
let mutable go = true
let mutable x2 = 4 * x * x
while go do
let n = x2 + y*y
if n <= topCandidate then
if Set.contains (n % 60) set1 then
Array.get sieve n |> not |> Array.set sieve n
y <- y + 2
else
y <- 1
x <- x + 1
x2 <- 4 * x * x
if topCandidate < x2 + 1 then
go <- false
// Flip solutions of the second equation
let doSecond sieve topCandidate =
let set2 = Set.ofList [7; 19; 31; 43]
let mutable x = 1
let mutable y = 2
let mutable go = true
let mutable x2 = 3 * x * x
while go do
let n = x2 + y*y
if n <= topCandidate then
if Set.contains (n % 60) set2 then
Array.get sieve n |> not |> Array.set sieve n
y <- y + 2
else
y <- 2
x <- x + 2
x2 <- 3 * x * x
if topCandidate < x2 + 4 then
go <- false
// Flip solutions of the third equation
let doThird sieve topCandidate =
let set3 = Set.ofList [11; 23; 47; 59]
let mutable x = 2
let mutable y = x - 1
let mutable go = true
let mutable x2 = 3 * x * x
while go do
let n = x2 - y*y
if n <= topCandidate && 0 < y then
if Set.contains (n % 60) set3 then
Array.get sieve n |> not |> Array.set sieve n
y <- y - 2
else
x <- x + 1
y <- x - 1
x2 <- 3 * x * x
if topCandidate < x2 - y*y then
go <- false
// Sieve of Atkin
let ListAtkin (topCandidate : int) =
let sieve = initSieve topCandidate
[async { doFirst sieve topCandidate }
async { doSecond sieve topCandidate }
async { doThird sieve topCandidate }]
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
removeSquares sieve topCandidate |> pickPrimes
let rec primes =
seq {
yield 2
yield! (Seq.unfold (fun i -> Some(i, i + 2)) 3)
|> Seq.filter (fun p ->
primes
|> Seq.takeWhile (fun i -> i * i <= p)
|> Seq.forall (fun i -> p % i <> 0))
}
for i in primes do
printf "%d " i
let rec isprime x =
primes
|> Seq.takeWhile (fun i -> i*i <= x)
|> Seq.forall (fun i -> x%i <> 0)
and primes =
seq {
yield 2
yield! (Seq.unfold (fun i -> Some(i,i+2)) 3)
|> Seq.filter isprime
}