Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.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/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
C++ 与C++;_C++_Performance_Haskell - Fatal编程技术网

C++ 与C++;

C++ 与C++;,c++,performance,haskell,C++,Performance,Haskell,我有一个任务,我需要在哈斯克尔解决。 首先用C++解决,然后将代码重写为Haskell。 该算法工作正常,但Haskell版本运行速度较慢,与C++版本相比。 例如,对于输入: 110110100011010101010101 010101101001000101010100 哈斯克尔(与GHCI):20秒 哈斯克尔(编译GHC):3秒 C++:1或1->0)使源数组与目标数组相同。切换有一条规则:只有当i+1为1且i+2->n为0时,才能更改i的状态,最后一个除外 C++代码: #inclu

我有一个任务,我需要在哈斯克尔解决。 首先用C++解决,然后将代码重写为Haskell。 该算法工作正常,但Haskell版本运行速度较慢,与C++版本相比。 例如,对于输入:

110110100011010101010101
010101101001000101010100
哈斯克尔(与GHCI):20秒 哈斯克尔(编译GHC):3秒 C++:1或1->0)使源数组与目标数组相同。切换有一条规则:只有当i+1为1且i+2->n为0时,才能更改i的状态,最后一个除外

C++代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

//flips the i-th char int s to match the i-th char in t
int flip2(int i, string& s, char t){
    if(i>=s.length() || s[i]==t) return 0; //if matches, or non-existent index, returns 0 steps
    int c=1; // 1 step is switching the character
    c+=flip2(i+1,s,'1'); //in order to switch i, i+1 have to be 1
    for(int j=i+2;j<s.length();j++) //in order to switch i, i+2->n have to be 0
        c+=flip2(j,s,'0');
    s[i]=t;
    return c;
}

//returns the minimum number of switch steps to make s=t
int ultimateFlip( string s, string t){
    int c=0;
    for(int i=0;i<s.length();i++){ // switches every character in s to match t
        c+=flip2(i,s,t[i]); //adds up the steps
    }
    return c;
}

int main()
{
    string s; // source array (made up of 0s and 1s)
    getline(cin, s);
    string t; //target array (made up of 0s and 1s)
    getline(cin, t);

    cout<<ultimateFlip(s,t);
}  
import System.IO
import Control.Monad

main :: IO ()
main = do
    hSetBuffering stdout NoBuffering
    
    s <- getLine -- source string
    t <- getLine -- target string
     
    let sol = ultimateFlip s t
    
    putStrLn $ show sol
    return ()

--returns the minimum number of switch steps to make s=t
ultimateFlip :: [Char] -> [Char] -> Int
ultimateFlip [] [] = 0
ultimateFlip (s:sx) (t:tx) = k + ultimateFlip sxn tx
    where
        (k,sxn)=flip2 s t sx --snx = new (after) version of sx(the rest of the string)

--flips the s to match t, sx= rest of the source string after s
flip2 :: Char->Char->[Char]->(Int,[Char])
flip2 s t sx
    | s == t = (0,sx) --if mathes, no switch needed
    | null sx = (1,sx) --if last one, one switch need
    | otherwise = (k2+k1+1,'1':nsx2)
        where
            (sxh:sxt) = sx
            (k1,nsx1) = flip2 sxh '1' sxt --switch next to 1
            (k2,nsx2) = zeroOut nsx1 --switch everything after the next to 0

--switch everything to 0
zeroOut :: [Char] -> (Int, [Char])
zeroOut [] = (0,[])
zeroOut (s:sx) = (k1+k2,'0':nsx2)
    where
        (k1,nsx1) = flip2 s '0' sx
        (k2,nsx2) = zeroOut nsx1
#包括
#包括
#包括
#包括
使用名称空间std;
//翻转第i个字符int s以匹配t中的第i个字符
int flip2(int i、字符串与序列、字符t){
if(i>=s.length()| | s[i]==t)返回0;//如果匹配或不存在索引,则返回0步
int c=1;//第一步是切换字符
c+=flip2(i+1,s,'1');//要切换i,i+1必须为1
对于(int j=i+2;jn必须为0
c+=flip2(j,s,'0');
s[i]=t;
返回c;
}
//返回使s=t的最小开关步数
int ultimateFlip(字符串s、字符串t){
int c=0;
for(int i=0;i(int,[Char])
flip2 s t sx
|s==t=(0,sx)——如果是mathes,则不需要开关
|null sx=(1,sx)--如果是最后一个,则需要一个开关
|否则=(k2+k1+1,'1':nsx2)
哪里
(sxh:sxt)=sx
(k1,nsx1)=flip2 sxh'1'sxt--1旁边的开关
(k2,nsx2)=调零nsx1——将下一个值之后的所有内容切换到0
--将所有内容切换到0
zeroOut::[Char]->(Int[Char])
归零[]=(0,[])
调零(s:sx)=(k1+k2,'0':nsx2)
哪里
(k1,nsx1)=翻转2 s'0'sx
(k2,nsx2)=调零nsx1
对于Haskell,我使用的是:GHC,8.10.2版

对于C++,我使用的是:GCC(GCC):102.0/p>< P>最大的问题是缺乏严格性。.Haskell的延迟求值意味着,即使是像
k2+k1+1
这样的简单计算,在需要答案之前通常也不会求值。由于递归函数执行了一系列这样的加法,有时您可能会构建一个巨大的未求值表达式,在最终求值之前会占用大量内存最后

在这里,通过在顶部添加语言扩展:

{-# LANGUAGE BangPatterns #-}
并在
flip
的“where”子句中添加一个严格的“!”注释:

<>这将我的机器上的运行时间从800毫秒降低到80ms(再次,用<代码> GHC-O2编译)。这仍然比C++版本(20ms)慢,但它在正确的PARCGPE中。< /P> 这里的注释具有强制计算表达式的效果。找出需要严格注释的位置有点困难。在这种情况下,我怀疑是您的计数导致了问题,所以我加入了“!”在返回计数的所有位置之前,然后我将它们删除,直到找到最重要的位置


剩下的速度差异可能是由于在Haskell中使用了大量的列表处理(与C++中的数组相比),因此您可能会做得更好,尽管我不确定这是否值得麻烦。

您正在花费大量时间分配和立即解构对。这是非常不必要的,因为您总是知道在元组的后半部分将返回什么。以下是消除此问题的一种方法:

ultimateFlip::[Char]->[Char]->Int
ultimateFlip[][]=0
终极翻转(s:sx)(t:tx)
|s==t=ultimateFlip sx tx
|空sx=1
|否则=ultimateFlip sx tx'+1+ultimateFlip tx'tx,其中

tx'='1':('0'“对于Haskell,我使用的是:GHCi,8.10.2版”,但我怀疑你能否以C/C++的速度获得Haskell,至少在没有专门“技巧”的情况下是如此,这不是同类比较。您需要实际编译Haskell代码,并进行优化,以便进行公平的比较-而不仅仅是使用GHCi运行。您应该使用
ghc-O…
将其编译为可执行文件。
GHCi
不是为了对函数进行基准测试而设计的。如果您对代码进行了注释,这会很有帮助。但是从我所看到的,Haskell的索引将慢得多,因为它使用链接列表,而C++对其字符串有随机访问。试试<代码>数据。矢量< /代码>或者正确解释函数应该做什么,也许有更适合Haskell的算法。@昆比,对于什么是值得的,这个代码似乎没有做任何索引。@ DanielWagner我不是Haskell专家,但我认为索引隐藏在递归中,通过
flip2
返回一个元组,但我不确定,我会感谢OP对他们的代码进行评论。很好。在我的机器上,去掉bang模式并强制返回(如
|否则=k3`seq`(k3,'1':nsx2),其中k3=k2+k1
)使它更快一点。
(!k1,nsx1) = flip2 sxh '1' sxt
 ^