Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance F#惯用表演_Performance_F#_Idioms_Imperative - Fatal编程技术网

Performance F#惯用表演

Performance F#惯用表演,performance,f#,idioms,imperative,Performance,F#,Idioms,Imperative,我正在使用。第n个主要挑战是建立一个。单元测试让您搜索1001素数,即104743 我修改了我记忆中的一段代码片段以成批工作(需要10k个素数,而不是25个),并将其与我自己的命令式版本进行了比较。有一个显著的性能差异: (BenchmarkDotNet v0.11.2) 有没有一种有效的方法可以习惯地做到这一点?我喜欢F。我喜欢使用F#库可以节省多少时间。但有时我看不到一条有效的惯用路线 下面是惯用代码: // we only need to check numbers ending in

我正在使用。第n个主要挑战是建立一个。单元测试让您搜索1001素数,即104743

我修改了我记忆中的一段代码片段以成批工作(需要10k个素数,而不是25个),并将其与我自己的命令式版本进行了比较。有一个显著的性能差异:

(BenchmarkDotNet v0.11.2)

有没有一种有效的方法可以习惯地做到这一点?我喜欢F。我喜欢使用F#库可以节省多少时间。但有时我看不到一条有效的惯用路线

下面是惯用代码:

// we only need to check numbers ending in 1, 3, 7, 9 for prime
let getCandidates seed = 
    let nextTen seed ten = 
        let x = (seed) + (ten * 10)
        [x + 1; x + 3; x + 7; x + 9]
    let candidates = [for x in 0..9 do yield! nextTen seed x ]
    match candidates with 
    | 1::xs -> xs  //skip 1 for candidates
    | _ -> candidates


let filterCandidates (primes:int list) (candidates:int list): int list = 
    let isComposite candidate = 
        primes |> List.exists (fun p -> candidate % p = 0 )
    candidates |> List.filter (fun c -> not (isComposite c))

let prime nth : int option = 
    match nth with 
        | 0 -> None
        | 1 -> Some 2
        | _ ->
            let rec sieve seed primes candidates = 
                match candidates with 
                | [] -> getCandidates seed |> filterCandidates primes |> sieve (seed + 100) primes //get candidates from next hunderd
                | p::_ when primes.Length = nth - 2 -> p //value found; nth - 2 because p and 2 are not in primes list
                | p::xs when (p * p) < (seed + 100) -> //any composite of this prime will not be found until after p^2
                    sieve seed (p::primes) [for x in xs do if (x % p) > 0 then yield x]
                | p::xs -> 
                    sieve seed (p::primes) xs


            Some (sieve 0 [3; 5] [])
//我们只需要检查素数以1、3、7、9结尾的数字
让GetSeed=
让下一个种子10=
设x=(种子)+(十*10)
[x+1;x+3;x+7;x+9]
让候选者=[对于0..9中的x,确实产生!下一个种子x]
将候选人与
|1::xs->xs//对于候选人跳过1
|->候选人
let filterCandidates(素数:int list)(候选项:int list):int list=
让isComposite候选者=
素数|>List.exists(乐趣p->候选者%p=0)
候选项|>List.filter(趣味c->not(isComposite c))
设素数n:int选项=
匹配
|0->无
|1->一些2
| _ ->
让rec筛选候选种子素数=
将候选人与
|[]->getCandidates seed |>filterCandidates primes |>sive(seed+100)primes//从下一个百年中获取候选项
|p::u当primes.Length=nth-2->p//找到值时;因为p和2不在素数列表中
|p::xs when(p*p)<(seed+100)->//在p^2之后才能找到此素数的任何组合
筛分种子(p::素数)[对于x中的x,如果(x%p)>0,则产生x]
|p::xs->
筛种(p::素数)xs
一些(0[3;5][])
这是当务之急:

type prime = 
    struct 
        val BaseNumber: int
        val mutable NextMultiple: int
        new (baseNumber) = {BaseNumber = baseNumber; NextMultiple = (baseNumber * baseNumber)}
        //next multiple that is odd; (odd plus odd) is even plus odd is odd
        member this.incrMultiple() = this.NextMultiple <- (this.BaseNumber * 2) + this.NextMultiple; this 
    end

let prime nth : int option = 
    match nth with 
    | 0 -> None
    | 1 -> Some 2
    | _ ->
        let nth' = nth - 1 //not including 2, the first prime
        let primes = Array.zeroCreate<prime>(nth')
        let mutable primeCount = 0
        let mutable candidate = 3 
        let mutable isComposite = false
        while primeCount < nth' do

            for i = 0 to primeCount - 1 do
                if primes.[i].NextMultiple = candidate then
                    isComposite <- true
                    primes.[i] <- primes.[i].incrMultiple()

            if isComposite = false then 
                primes.[primeCount] <- new prime(candidate)
                primeCount <- primeCount + 1

            isComposite <- false
            candidate <- candidate + 2

        Some primes.[nth' - 1].BaseNumber
type prime=
结构
val基本编号:int
val可变NextMultiple:int
新的(baseNumber)={baseNumber=baseNumber;NextMultiple=(baseNumber*baseNumber)}
//下一个倍数是奇数;(奇数加奇数)是偶数加奇数是奇数
成员this.incrmmultiple()=this.NextMultiple None
|1->一些2
| _ ->
设n'=n-1//不包括2,第一个素数
设primes=Array.zeroCreate(n')
设可变素数=0
设可变候选者=3
设可变isComposite=false
而primeCountisComposite乍一看,你并不是在比较相同的概念。当然,我不是在谈论函数式与命令式,而是算法背后的概念

您的维基参考资料最能说明这一点:

这是筛子的关键区别,不同于使用试除法顺序测试每个候选数是否被每个素数整除

换言之,埃拉托什尼权力的筛子在于不使用审判分庭。另一个:

试除法是整数分解算法中最费力但最容易理解的一种

这就是你在过滤器中所做的

let isComposite candidate =  
    primes |> List.exists (fun p -> candidate % p = 0 ) 

因此,一般来说,在使用函数式习惯用法时,您可能希望比使用命令式模型时慢一点,因为您必须创建新对象,这比修改现有对象花费的时间要长得多

对于这个问题,特别是当使用F#列表时,与使用数组相比,每次都需要迭代素数列表是一种性能损失。您还应该注意,您不需要单独生成候选列表,只需循环并动态添加2个。也就是说,最大的性能胜利可能是使用变异来存储您的
nextNumber

type prime = {BaseNumber: int; mutable NextNumber: int}
let isComposite (primes:prime list) candidate = 
    let rec inner primes candidate =
        match primes with 
        | [] -> false
        | p::ps ->
            match p.NextNumber = candidate with
            | true -> p.NextNumber <- p.NextNumber + p.BaseNumber*2
                      inner ps candidate |> ignore
                      true
            | false -> inner ps candidate
    inner primes candidate


let prime nth: int option = 
    match nth with 
    | 0 -> None
    | 1 -> Some 2
    | _ -> 
            let rec findPrime (primes: prime list) (candidate: int) (n: int) = 
                match nth - n with 
                | 1 -> primes
                | _ -> let isC = isComposite primes candidate
                       if (not isC) then
                           findPrime ({BaseNumber = candidate; NextNumber = candidate*candidate}::primes) (candidate + 2) (n+1)
                       else
                           findPrime primes (candidate + 2) n
            let p = findPrime [{BaseNumber = 3; NextNumber = 9};{BaseNumber = 5; NextNumber = 25}] 7 2
                    |> List.head
            Some(p.BaseNumber)
type prime={BaseNumber:int;可变NextNumber:int}
设isComposite(素数:素数列表)候选项=
让rec内素数作为候选=
将素数与
|[]->false
|p::ps->
将p.NextNumber=候选人与
|true->p.NextNumber忽略
真的
|false->内部ps候选
内素数候选
设素数n:int选项=
匹配
|0->无
|1->一些2
| _ -> 
让rec findprome(素数:素数列表)(候选者:int)(n:int)=
将n-n与
|1->素数
|->让isC=isComposite素数候选
如果(不是isC)那么
FindTime({BaseNumber=candidate;NextNumber=candidate*candidate}::primes)(candidate+2)(n+1)
其他的
FindTime素数(候选者+2)n
设p=findprome[{BaseNumber=3;NextNumber=9};{BaseNumber=5;NextNumber=25}]7 2
|>列表头
一些(p.BaseNumber)

通过运行
#time
,我可以运行大约500毫秒
prime 10001
。相比之下,“命令式”代码大约需要250ms,“idomatic”代码大约需要1300ms。

我明白了。另外,公平地说,斯科特·沃拉钦说这是“质数筛的粗略实现”,它是为了找到前25个质数,而不是前10k。但问题仍然存在,什么是高效、惯用的实现?我的大脑直接进入命令式,我正在努力学习一种新的方法。@EricP for F#惯用的方法是混合命令式和声明式代码。不要将F#与Haskell混淆。@EricP:为了接近惯用的函数解决方案性能方面,您可能需要从中查看
primes
F#序列定义。我相信
primes |>Seq.item 10001
可能会