#cpp #haskell #benchmark
Сравниваю производительность. В качестве примера взята эта задача. Решение на Си++ #include#include #include #include #include #include #include using namespace boost; typedef boost::multiprecision::cpp_int LL; const char MSG_ERR[] = "Error\n"; const size_t MSG_ERR_LEN = std::strlen(MSG_ERR); rational *x; rational fun(const rational & y, const rational & z) { rational ret = 108 - (815 - (1500 / z))/y; return ret; } int main(int argn, char *argv[]) { if(argn != 2) { std::cout.write(MSG_ERR, MSG_ERR_LEN); return 1; } int n = std::atoi(argv[1]) + 1; if(n < 1) { std::cout.write(MSG_ERR, MSG_ERR_LEN); return 1; } x = new rational [n]; x[0] = 4; x[1] = rational (17,4); for(int i = 2; i < n; ++i) x[i] = fun(x[i-1], x[i-2]); std::cout << x[n-1] << std::endl; return 0; } Haskell: import Data.Ratio import System.Environment f y z = 108 - (815 - 1500 / z) / y xlist = 4 : (17 % 4) : zipWith f (tail xlist) xlist main = do args <- getArgs case args of [arg1] -> do let x = read arg1 putStrLn $ show $ xlist !! x _ -> error "ERR: Main.Args" Результаты: C++: $ clang++37 -O3 -I/usr/local/include -o CPP t1.cpp $ time ./CPP 10000 > /dev/null 39,64 real 39,62 user 0,00 sys Haskell: $ ghc -O2 t1.hs -o HS Linking HS ... $ time ./HS 10000 > /dev/null 6,73 real 6,73 user 0,00 sys Чем можно объяснить столь существенную разницу? Буст? Лень?
Ответы
Ответ 1
Столь существенную разницу можно объяснить тем что boost не максимально оптимизирован, хотя результат намного лучше чем писать длинную арифметику вручную. Теперь рассмотрим какой потенциал мы можем выжать из С++. Для этого будем использовать библиотеку GMP, возьмём этот код: #include#include #include #include const char MSG_ERR[] = "Error\n"; const size_t MSG_ERR_LEN = std::strlen(MSG_ERR); mpq_class fun(const mpq_class & y, const mpq_class & z) { mpq_class ret = 108 - (815 - (1500 / z))/y; return ret; } int main(int argc, char *argv[]) { if(argc != 2) { std::cout.write(MSG_ERR, MSG_ERR_LEN); return 1; } int n = std::atoi(argv[1]) + 1; if(n < 1) { std::cout.write(MSG_ERR, MSG_ERR_LEN); return 1; } std::vector v; v.push_back(mpq_class(4, 1)); v.push_back(mpq_class(17, 4)); for (int i = 2; i < n; ++i) { v.push_back(fun(v[i - 1], v[i - 2])); } std::cout << v.rbegin()->get_num() << " / " << v.rbegin()->get_den() << std::endl; return 0; } И соберём все результаты в кучу, на своей машине я получил такой результат: Haskell > ghc -O2 test.hs -o HS > time ./HS 10000 > /dev/null real 0m7.491s user 0m7.420s sys 0m0.004s C++, boost > g++-5 -O2 -o CPP test.cpp > time ./CPP 10000 > /dev/null real 0m22.272s user 0m22.256s sys 0m0.012s > clang++ -O2 -o CPP-CLANG test.cpp > time ./CPP-CLANG 10000 > /dev/null real 0m20.638s user 0m20.628s sys 0m0.008s C++, gmp > g++-5 -O2 -std=c++14 -lgmpxx -lgmp -o CPP-GMP testgmp.cpp > time ./CPP-GMP 10000 > /dev/null real 0m1.418s user 0m1.404s sys 0m0.016s Мы убедились, что boost не даёт нам максимальную производительность.
Комментариев нет:
Отправить комментарий