Страницы

Поиск по вопросам

среда, 29 января 2020 г.

C++ vs Haskell: производительность

#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 не даёт нам максимальную производительность.

Комментариев нет:

Отправить комментарий