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
哈斯克尔vs C速度:埃拉托斯坦筛_C_Performance_Haskell_Math_Implementation - Fatal编程技术网

哈斯克尔vs C速度:埃拉托斯坦筛

哈斯克尔vs C速度:埃拉托斯坦筛,c,performance,haskell,math,implementation,C,Performance,Haskell,Math,Implementation,Haskell one是使用复杂度为O(lg n)的优化Data.IntSet实现的。然而,尽管Haskell代码已经针对偶数情况进行了优化,但n=2000000时存在15倍(以前为30倍)的速度差。我想知道我在Haskell中的实现是否/为什么不完善 原始哈斯克尔 更新 fromDistinctAscList可将速度提高4倍。2-3-5-7轮速度再提高50% primesUpTo :: Int -> [Int] primesUpTo n = 2 : 3 : 5 : 7 : put S.e

Haskell one是使用复杂度为O(lg n)的优化Data.IntSet实现的。然而,尽管Haskell代码已经针对偶数情况进行了优化,但n=2000000时存在15倍(以前为30倍)的速度差。我想知道我在Haskell中的实现是否/为什么不完善

原始哈斯克尔 更新
fromDistinctAscList
可将速度提高4倍。2-3-5-7轮速度再提高50%

primesUpTo :: Int -> [Int]
primesUpTo n = 2 : 3 : 5 : 7 : put S.empty (takeWhile (<=n) (spin wheel 11))
    where put :: S.IntSet -> [Int] -> [Int]
          put _ [] = []
          put comps (x:xs) =
            if S.member x comps
            then put comps xs
            else x : put (S.union comps multiples) xs
                where multiples = S.fromDistinctAscList [x*x, x*(x+2) .. n]
          spin (x:xs) n = n : spin xs (n + x)
          wheel = 2:4:2:4:6:2:6:4:2:4:6:6:2:6:4:2:6:4:6:8:4:2:4:2:4:8:6:4:6:2:4:6:2:6:6:4:2:4:6:2:6:4:2:4:2:10:2:10:wheel
优化的Haskell比C++ BoL慢10~15X,比C++集快10x/

源代码 C编译器选项:g++5.3.1,

g++-std=C++11
Haskell选项:ghc 7.8.4,
ghc

C代码(布尔数组)

prime[0]=prime[1]=false;
对于(int i=2;i
我想知道我在Haskell中的实现是否/为什么不完善

最好使用线性执行。您也可以只添加以x*x开始的奇数倍数,而不是x*2,因为所有较小的奇数倍数都已添加。就样式而言,右倍可能比递归更适合

这样,我在n等于2000000的情况下获得了3倍以上的性能提升:

import Data.IntSet (member, union, empty, fromDistinctAscList)

sieve :: Int -> [Int]
sieve n = 2: foldr go (const []) [3,5..n] empty
    where
    go i run obs
        | member i obs = run obs
        | otherwise    = i: run (union obs inc)
        where inc = fromDistinctAscList [i*i, i*(i + 2)..n]
{-# LANGUAGE FlexibleContexts #-}
import Data.Array.ST (STUArray)
import Control.Monad (forM_, foldM)
import Control.Monad.ST (ST, runST)
import Data.Array.Base (newArray, unsafeWrite, unsafeRead)

sieve :: Int -> [Int]
sieve n = reverse $ runST $ do
    arr <- newArray (0, n) False :: ST s (STUArray s Int Bool)
    foldM (go arr) [2] [3,5..n]
    where
    go arr acc i = do
        b <- unsafeRead arr i
        if b then return acc else do
            forM_ [i*i, i*(i + 2).. n] $ \k -> unsafeWrite arr k True
            return $ i: acc
然而,数组同时具有O(1)访问和缓存友好型内存分配。使用可变数组,我看到性能比Haskell代码提高了15倍以上(同样,n等于2000000):

{-#语言灵活上下文}
导入Data.Array.ST(STUArray)
导入控制.Monad(表单,foldM)
import Control.Monad.ST(ST,runST)
导入Data.Array.Base(newArray、unsafeWrite、unsafeRead)
筛:Int->[Int]
筛n=反向$runST$do

arr将
pastebin
更改为
pastehere
…数组访问是
O(1)
,而不是
O(logn)
——因此我不希望代码具有可比性。另外,如果Haskell使用任意精度的算术(我认为是这样的)C使用的是固定长度的整数,这可能会有差异。如果你想做这种基准测试,请展示整个程序(Haskell程序和你正在比较的C),使用的编译器版本和编译选项,以及计时是如何记录的。这不是不可能的(例如)找到素数根本不需要时间,而且打印速度很慢。此外,Haskell很懒,有一个习惯,就是不计算你认为它在计算的东西。所以,请向我们展示整个程序以及你实际测量的东西。源在哪里?“Haskell选项:
ghc
”我是否认为您没有使用
-O
开关来启用编译器优化?(我不知道这是否有什么区别,我只是检查一下。)谢谢!但是如果
STUArray
快得多,那么除了
findMin
findMax
之外,使用
IntSet
还有什么理由呢?@MarcoXerox有两件事:
STUArray
不是一个纯粹的函数结构,这意味着你只能在
ST
中运行它(状态线程),而
IntSet
是完全纯净的,因此您可以将其传递并在整个程序中使用。第二件事是,每个数据结构都有它擅长的东西和它不擅长的东西。对于一个筛子来说,可变数组简直就是王牌。这并不意味着数组总是最好使用的——当然不是y在C中经常使用,而列表在Python中也同样无处不在。但是,无可否认,作为一名Haskell新手,我读过的大多数教程都只使用数组作为记忆工具;相反,它们使用链表、序列等,这些都是纯函数式的。相反,数组、堆、段树等提供了更好的查找时间。我可以enclC风格函数中的ose数组操作和传递它们的返回指针。我不太理解纯函数结构的好处。
 prime[0] = prime[1] = false;
 for (int i=2; i<=limit; i++) { //edited
     if (!prime[i]) continue;
     for (int j=2*i; j<=n; j+=i)
        prime[j] = false;
 }
 nonprime.insert(1);
 for (int i=2; i<=limit; i++) { //edited
     if (nonprime.count(i) > 0) continue;
     for (int j=2*i; j<=n; j+=i)
        nonprime.insert(j);
 }
import Data.IntSet (member, union, empty, fromDistinctAscList)

sieve :: Int -> [Int]
sieve n = 2: foldr go (const []) [3,5..n] empty
    where
    go i run obs
        | member i obs = run obs
        | otherwise    = i: run (union obs inc)
        where inc = fromDistinctAscList [i*i, i*(i + 2)..n]
{-# LANGUAGE FlexibleContexts #-}
import Data.Array.ST (STUArray)
import Control.Monad (forM_, foldM)
import Control.Monad.ST (ST, runST)
import Data.Array.Base (newArray, unsafeWrite, unsafeRead)

sieve :: Int -> [Int]
sieve n = reverse $ runST $ do
    arr <- newArray (0, n) False :: ST s (STUArray s Int Bool)
    foldM (go arr) [2] [3,5..n]
    where
    go arr acc i = do
        b <- unsafeRead arr i
        if b then return acc else do
            forM_ [i*i, i*(i + 2).. n] $ \k -> unsafeWrite arr k True
            return $ i: acc