Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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/r/75.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 Haskell函数的运行效率分析_Performance_Haskell_Optimization - Fatal编程技术网

Performance Haskell函数的运行效率分析

Performance Haskell函数的运行效率分析,performance,haskell,optimization,Performance,Haskell,Optimization,我在Haskell中有以下解决方案: isPrime::Integer->Bool isPrime p=(除数p)=[1,p] 除数::整数->[整数] 除数n=[d | d让我们从顶部开始 divisors :: Integer -> [Integer] divisors n = [d | d <- [1..n], n `mod` d == 0] 在最坏的情况下,p是素数,它强制除数生成其整个输出。与静态已知长度列表的比较是O(1),因此这主要由对除数的调用决定。O(n),O(2

我在Haskell中有以下解决方案:

isPrime::Integer->Bool
isPrime p=(除数p)=[1,p]
除数::整数->[整数]

除数n=[d | d让我们从顶部开始

divisors :: Integer -> [Integer]
divisors n = [d | d <- [1..n], n `mod` d == 0]
在最坏的情况下,
p
是素数,它强制
除数
生成其整个输出。与静态已知长度列表的比较是O(1),因此这主要由对
除数的调用决定。O(n),O(2^m)

您的
main
函数一次执行一系列操作,因此让我们稍微分解一下子表达式

filter ((==0) . (n `mod`))
它在一个列表上循环,并对每个元素执行O(1)操作。这是O(m),其中m是输入列表的长度

filter isPrime
在列表上循环,对每个元素做O(n)功,其中n是列表中的最大数。如果列表恰好有n个元素长(在您的例子中),这意味着这是O(n*n)功,或者O(2^m*2^m)=O(4^m)功(如上所述,此分析针对的是它生成整个列表的情况)

微小的工作。让我们称之为印刷部分的O(m)

main = print (head (filter isPrime (filter ((==0) . (n `mod`)) [n-1,n-2..])))
考虑到上面的所有子表达式,
过滤器isPrime
位显然是主要因素。O(4^m),O(n^2)

现在,还有最后一个需要考虑的细节:在上面的分析中,我一直假设每个函数/子表达式都必须生成其整个输出。正如我们在
main
中看到的,这可能不是真的:我们调用
head
,这只会强制列表中的一小部分。但是,如果ber本身不是素数,我们可以肯定地知道,我们必须查看至少一半的列表:在
n/2
n
之间肯定不会有除数。因此,我们最好将我们的工作减半——这对渐近成本没有影响。

两件事:

  • 任何时候,当你看到一个列表理解(就像你在
    除数中看到的那样),或者等价地,一些
    映射
    和/或
    过滤
    函数在一个列表上(就像你在
    main
    中看到的那样),把它的复杂性当作Θ(n),就像你在命令式语言中对待
    for
    -循环一样

  • 这可能不是您所期望的那种建议,但我希望它会更有帮助:欧拉计划的部分目的是鼓励您思考各种数学概念的定义,以及可能正确满足这些定义的许多不同算法

  • 好的,第二个建议有点含糊不清……我的意思是,例如,您实现
    isPrime
    的方式实际上是教科书上的定义:

    isPrime :: Integer -> Bool
    isPrime p = (divisors p) == [1, p]
    -- p is prime if its only divisors are 1 and p. 
    
    同样地,
    除数
    的实现也很简单:

    divisors :: Integer -> [Integer]
    divisors n = [d | d <- [1..n], n `mod` d == 0]
    -- the divisors of n are the numbers between 1 and n that divide evenly into n.
    
    除数::整数->[整数]
    除数n=[d | d很好地解释了推导运行时复杂性边界的一般策略。然而,与一般策略的情况一样,它产生的边界过于保守

    所以,让我们更详细地研究一下这个例子

    main = print (head (filter isPrime (filter ((==0) . (n `mod`)) [n-1,n-2..])))
        where n = 600851475143
    
    (旁白:如果
    n
    为素数,则在检查
    n`mod`0==0
    时会导致运行时错误,因此我将列表更改为
    [n,n-1..2]
    ,以便算法适用于所有
    n>1

    让我们将表达式分成几个部分,以便更容易地查看和分析每个部分

    main = print answer
      where
        n = 600851475143
        candidates = [n, n-1 .. 2]
        divisorsOfN = filter ((== 0) . (n `mod`)) candidates
        primeDivisors = filter isPrime divisorsOfN
        answer = head primeDivisors
    
    和Daniel一样,我的工作假设算术运算、比较等都是O(1)——虽然不是真的,但对于所有遥远的合理输入来说,这是一个足够好的近似值


    因此,在
    候选列表中,必须生成从
    n
    answer
    的元素,
    n-answer+1
    元素,总成本为
    O(n-answer+1)
    。对于复合
    n
    ,我们找到了
    答案1
    ,确定了相等性测试。对于复合
    p
    ,最小的素因子是
    ,这里是代码分析/优化的一个很好的参考:。但是,在深入研究之前,我会重新考虑您正在使用的算法。@jtobin通过“运行时效率”我用大O符号在理论层面思考。我可以用命令式语言进行这种类型的分析。我对函数式语言很陌生,所以这种类型的分析对我来说很棘手。“重新思考我的算法”这正是我所想的。所有答案的净问题是,它们没有得到任何这样的暴力代码进行素因子分解的结果,而它可能代表一种“计算方法”,可以得到一个解决方案……它不会在任何合理的时间和功耗内这样做。这不是“代码”问题是“我如何开发更好的算法或“近似算法”(一个通常能更快地给出答案的方法,但可能不会。请参阅素数分解研究。)有趣的是,我今天早上醒来后就在想这件事。如果我在C/C++/Java中编写for循环来测试素数,我会停在sqrt n。现在我只需要弄清楚如何在Haskell中做同样的事情。谢谢你的评论!@Code Guru最简单的方法就是使用takeWhile(\k->k*k@danielfisher我不是在问怎么做=谢谢你回答我的问题。这就是我要求的那种复杂性分析,即使我没有使用那些确切的词语。谢谢你回答我的问题。这是我要求的那种复杂性分析,即使我没有使用那些确切的词语。
    
    divisors :: Integer -> [Integer]
    divisors n = [d | d <- [1..n], n `mod` d == 0]
    -- the divisors of n are the numbers between 1 and n that divide evenly into n.
    
    main = print (head (filter isPrime (filter ((==0) . (n `mod`)) [n-1,n-2..])))
        where n = 600851475143
    
    main = print answer
      where
        n = 600851475143
        candidates = [n, n-1 .. 2]
        divisorsOfN = filter ((== 0) . (n `mod`)) candidates
        primeDivisors = filter isPrime divisorsOfN
        answer = head primeDivisors
    
    isPrime :: Integer -> Bool
    isPrime p = (divisors p) == [1, p]