【发布时间】:2016-06-22 00:12:13
【问题描述】:
Haskell 标签中的问题通常是为什么 Haskell 与 X 相比如此慢。大多数情况下,您可以将其归结为 String 而不是 Text 或 ByteString 的用法。非严格评估或缺少类型签名。
但是这里我有一个简单的斐波那契计算器,它的性能比 C++ 高出大约 2 倍。这可能是缺乏 C++ 知识 - 但我从一个朋友那里得到了代码,他曾经在这种语言。
★ g++ -O3 fib2.cc -o cc-fib -lgmpxx -lgmp
★ time ./cc-fib > /dev/null
./cc-fib > /dev/null 8,23s user 0,00s system 100% cpu 8,234 total
★ ghc -O3 --make -o hs-fib fib1.hs
[1 of 1] Compiling Main ( fib1.hs, fib1.o )
Linking hs-fib ...
★ time ./hs-fib > /dev/null
./hs-fib > /dev/null 4,36s user 0,03s system 99% cpu 4,403 total
在 haskell 文件中,我只使用了一个严格的zipWith' 和一个严格的add' 函数(这是使用扩展名BangPatterns 的地方 - 它只是告诉编译器评估参数x/@987654329 @ 在执行添加之前)以及添加显式类型签名。
两个版本都使用 bigint,所以这似乎与我相当,而且 c++ 代码不使用具有指数运行时间的“标准”递归,但是一个应该表现良好的记忆版本(或者至少这是我的想法- 如果我错了,请纠正我)。
使用的设置是:
- 在相当新的笔记本电脑上运行 Linux 64 位 (Mint)
- ghc-7.10.3
- g++ 4.8.4 + libgmp-dev 2:5.1.3+dfsg-1ubuntu1
fib.cc
#include <iostream>
#include <gmpxx.h>
mpz_class fib(int n) {
mpz_class p1 = 0;
mpz_class p2 = 1;
mpz_class result;
if ( n == 0 ) return 0;
if ( n == 1 ) return 1;
for(int i = 2; i <= n ; i ++ ) {
result = p1 + p2;
p1 = p2;
p2 = result;
}
return result;
}
int main () {
std::cout<<fib(1000000)<<std::endl;
return 0;
}
fib.hs
{-# LANGUAGE BangPatterns -#}
module Main where
fib1 :: [Integer]
fib1 = 0:1:zipWith' (add') fib1 (tail fib1)
where zipWith' :: (Integer -> Integer -> Integer) -> [Integer] -> [Integer] -> [Integer]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = let z = f x y in z:zipWith' f xs ys
add' :: Integer -> Integer -> Integer
add' !x !y = let z = x + y in z `seq` z
fib4 :: [Integer]
fib4 = 0:1:zipWith (+) fib4 (tail fib4)
main :: IO ()
main = print $ fib1 !! 1000000
【问题讨论】:
-
这似乎更像是 GMP 的设计权衡与您的 Haskell 实现的 Integer 的问题,而不是 C++ 本身与 Haskell 的问题。
-
再想一想,您可能在 C++ 中做了一堆不必要的复制。我不确定
mpz_class的operator=是如何工作的。 -
引自主页“GMP 精心设计以尽可能快,无论是对于小操作数还是对于大操作数” 我认为 gmp 将是快速的正确选择执行。您能详细介绍一下这些设计选择吗?
-
@user2357112:GHC 使用 GMP,所以可能不是这样。 (从技术上讲,这只是一种可能的编译时配置,但我在实践中从未见过任何其他配置;我知道的另一种是“整数简单”,应该更慢。)
-
您可以通过将
p1 = p2; p2 = result;替换为p1.swap(p2); p2.swap(result);来加速C++ 实现
标签: c++ performance haskell