Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.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
Haskell 哈斯克尔:更快的素数求和_Haskell_Primes - Fatal编程技术网

Haskell 哈斯克尔:更快的素数求和

Haskell 哈斯克尔:更快的素数求和,haskell,primes,Haskell,Primes,免责声明:我正在研究Euler问题9 我把一些相当大的数字加起来,所有的素数从1到2000 求这些素数的和需要永远。我使用的是haskell内置函数“sum” 例如: sum listOfPrimes 还有其他更快的选择吗 --我的主生成器是代码中的慢速链接 听起来你的问题不是求和,而是生成它们。您对时间列表的实现是什么 这篇论文可能很有趣:我写了一篇“埃拉托斯坦筛”: 使用此功能,打印大约需要25秒。sum$takeWhile(我希望您使用的是ghc-O2,而不是ghci,对吗?您的问题将出

免责声明:我正在研究Euler问题9

我把一些相当大的数字加起来,所有的素数从1到2000

求这些素数的和需要永远。我使用的是haskell内置函数“sum”

例如:

sum listOfPrimes
还有其他更快的选择吗


--我的主生成器是代码中的慢速链接

听起来你的问题不是求和,而是生成它们。您对时间列表的实现是什么

这篇论文可能很有趣:

我写了一篇“埃拉托斯坦筛”:


使用此功能,打印
大约需要25秒。sum$takeWhile(我希望您使用的是ghc-O2,而不是ghci,对吗?您的问题将出现在下一代,而不是求和

一种更快的方法是使用基于流融合的序列,它可以更好地优化。对于常规列表:

import Data.List
import qualified Data.Map as M

primes :: [Integer]
primes = mkPrimes 2 M.empty
  where
    mkPrimes n m = case (M.null m, M.findMin m) of
        (False, (n', skips)) | n == n' ->
            mkPrimes (succ n) (addSkips n (M.deleteMin m) skips)
        _ -> n : mkPrimes (succ n) (addSkip n m n)
    addSkip n m s = M.alter (Just . maybe [s] (s:)) (n+s) m
    addSkips = foldl' . addSkip

-- fuse:
main = print (sum (takeWhile (<= 2000000) primes))
切换到流,因此sum.takeWhile保险丝:

import qualified Data.List.Stream as S
main = print (S.sum (S.takeWhile (<= 2000000) primes))
但你的问题将是素代,我们可以看到,如果我们完全放弃求和,用最后一个替换求和:

$ time ./A           
1999993
./A  9.65s user 0.12s system 99% cpu 9.768 total
因此,请找到一个更好的素数生成器。:-)

最后,有一个关于快速素数生成器的黑客库:

利用它,我们的时间变得:

$ cabal install primes
$ cabal install stream-fusion

$ cat A.hs
import qualified Data.List.Stream as S
import Data.Numbers.Primes

main = print . S.sum . S.takeWhile (<= 2000000) $ primes

$ ghc -O2 -fvia-C -optc-O3 A.hs --make

$ time ./A
142913828922
./A  0.62s user 0.07s system 99% cpu 0.694 total
$cabal安装底漆
$cabal安装流融合
$cat A.hs
将符合条件的Data.List.Stream作为S导入
导入数据。数字。素数

main=打印。苏姆。S.takeWhile(函数中缓慢的部分肯定是生成素数,而不是生成
sum
函数。生成素数的一个好方法是:

isprime :: (Integral i) => i -> Bool
isprime n = isprime_ n primes
  where isprime_ n (p:ps)
          | p*p > n        = True
          | n `mod` p == 0 = False
          | otherwise      = isprime_ n ps

primes :: (Integral i) => [i]
primes = 2 : filter isprime [3,5..]

我认为它可读性很强,尽管可能有点令人惊讶,因为它使用了递归和
primes
列表的惰性。它也相当快,尽管可以以可读性为代价进行进一步的优化。

因为你没有链接到它,|非常酷的东西,我没有意识到它被很好地打包在Hackage。嘿,我以前在Haskell中没有见过这种特殊的算法。非常酷,它比我的更简单,感觉也更像Haskell-y。这实际上相当于低效算法。它仍然根据每个素数测试每个数字。@newacc:它使用“低效”算法,但比“高效”算法更快版本,至少在这种情况下是这样。“高效”算法需要做大量的地图修改,并不断地在越来越大的地图上迭代。这不一定比几个素数好。确切地说。它感觉就像传统的
primes=sieve[2..]一样简单和干净,其中sieve(p:xs)=p:[x | x这是一个(几乎)最优试算法(OTD)筛,比“传统的”“低效”算法(即Turner
ps=sv[2..)的筛,其中sv(p:xs)=p:sv[x | x0]更有效
,因为它停止了对
n
的平方根的测试——由低于该数字本身的所有素数进行的特纳测试。OTD的理论时间复杂度为
O(k^1.5/(log k)^0.5)
(根据经验通常被视为
~k^1.45
),而对特纳测试的时间复杂度为
O(k^2)
,在
k
中生产素数。因此,在生产一百万素数时,OTD将
~2000x…4000x
(或更多)比Turner的筛子快。我同意!那个筛子帮了我很大的忙!非常好、清晰而且好!三个标准改进-仅赔率、推迟向地图添加素数以及双素数馈送-使它在2mln(测试)下运行速度加快10.6倍,在2000万(预测)下运行速度加快13.4倍。因此,运行时间将变为~1.9s。我已将更改后的代码添加到。:@WillNess Best reply:-)为什么,非常感谢。:…忘了提到它现在在接近恒定的空间(1..2MB)中运行。但这是意料之中的。
$ time ./A           
142913828922
./A  9.60s user 0.13s system 99% cpu 9.795 total
$ time ./A           
1999993
./A  9.65s user 0.12s system 99% cpu 9.768 total
$ cabal install primes
$ cabal install stream-fusion

$ cat A.hs
import qualified Data.List.Stream as S
import Data.Numbers.Primes

main = print . S.sum . S.takeWhile (<= 2000000) $ primes

$ ghc -O2 -fvia-C -optc-O3 A.hs --make

$ time ./A
142913828922
./A  0.62s user 0.07s system 99% cpu 0.694 total
isprime :: (Integral i) => i -> Bool
isprime n = isprime_ n primes
  where isprime_ n (p:ps)
          | p*p > n        = True
          | n `mod` p == 0 = False
          | otherwise      = isprime_ n ps

primes :: (Integral i) => [i]
primes = 2 : filter isprime [3,5..]