Подтвердить что ты не робот

Какой самый быстрый способ ввода в С++

Я кодирую различные олимпиады по программированию и тем самым улучшаю эффективность времени. Я ищу самый быстрый способ для ввода данных без необходимости добавления дополнительной библиотеки, то есть в стандартный доступный каталог в соответствии с компиляторами gcc, так как во время соревнований мы, очевидно, can not добавить библиотеки в компилятор. До сих пор на С++ я использовал cin и cout, но обнаружил, что scanf и printf намного быстрее, чем это, так что кто-нибудь может сказать мне более быстрый способ, это, может быть, настраиваемая функция, поскольку я не очень-то против космической сложности, но я предпочитаю время больше. Спасибо, продвинутый.

4b9b3361

Ответ 1

Эти потоки всегда медленнее, чем функции C-API - довольно распространенное заблуждение, поскольку по умолчанию они синхронизируются с C-слоем. Так что да, это особенность, а не ошибка.

Без ущерба для безопасности типа (и удобочитаемости, в зависимости от вашего вкуса) вы, возможно, получаете производительность с потоками, используя:

std::ios_base::sync_with_stdio (false);

Маленький индикатор:

#include <cstdio>
#include <iostream>

template <typename Test> 
void test (Test t)
{
    const clock_t begin = clock();
    t();
    const clock_t end = clock();
    std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}

void std_io() {
    std::string line;
    unsigned dependency_var = 0;

    while (!feof (stdin)) {
        int c;
        line.clear();
        while (EOF != (c = fgetc(stdin)) && c!='\n')
            line.push_back (c);
        dependency_var += line.size();
    }

    std::cout << dependency_var << '\n';
}

void synced() {
    std::ios_base::sync_with_stdio (true);
    std::string line;
    unsigned dependency_var = 0;
    while (getline (std::cin, line)) {
        dependency_var += line.size();
    }
    std::cout << dependency_var << '\n';
}

void unsynced() {
    std::ios_base::sync_with_stdio (false);
    std::string line;
    unsigned dependency_var = 0;
    while (getline (std::cin, line)) {
        dependency_var += line.size();
    }
    std::cout << dependency_var << '\n';
}

void usage() { std::cout << "one of (synced|unsynced|stdio), pls\n"; }

int main (int argc, char *argv[]) {
    if (argc < 2) { usage(); return 1; }

    if (std::string(argv[1]) == "synced") test (synced);
    else if (std::string(argv[1]) == "unsynced") test (unsynced);
    else if (std::string(argv[1]) == "stdio") test (std_io);
    else { usage(); return 1; }

    return 0;
}

С g++ -O3 и большим текстовым файлом:

cat testfile | ./a.out stdio
...
0.34 sec

cat testfile | ./a.out synced
...
1.31 sec

cat testfile | ./a.out unsynced
...
0.08 sec

Как это относится к вашему делу. Измените эту игрушку-тест, добавьте больше тестов и сравните, например. что-то вроде std::cin >> a >> b >> c с scanf ("%d %d %d", &a, &b, &c);. Я гарантирую, что с оптимизацией (т.е. Не находясь в режиме отладки) различия в производительности будут незначительными.

Если это не насыщает ваши потребности, вы можете попробовать другие подходы, например. сначала считывая весь файл (может или не может принести больше производительности) или карты памяти (что является не переносным решением, но у них большие рабочие столы).


Update

Отформатированный вход: scanf vs. streams

#include <cstdio>
#include <iostream>

template <typename Test> 
void test (Test t)
{
    const clock_t begin = clock();
    t();
    const clock_t end = clock();
    std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}

void scanf_() {
    char x,y,c;
    unsigned dependency_var = 0;

    while (!feof (stdin)) {
        scanf ("%c%c%c", &x, &y, &c);
        dependency_var += x + y + c;
    }

    std::cout << dependency_var << '\n';
}

void unsynced() {
    std::ios_base::sync_with_stdio (false);
    char x,y,c;
    unsigned dependency_var = 0;
    while (std::cin) {
        std::cin >> x >> y >> c;
        dependency_var += x + y + c; 
    }
    std::cout << dependency_var << '\n';
}

void usage() { std::cout << "one of (scanf|unsynced), pls\n"; }

int main (int argc, char *argv[]) {
    if (argc < 2) { usage(); return 1; }

    if (std::string(argv[1]) == "scanf") test (scanf_);
    else if (std::string(argv[1]) == "unsynced") test (unsynced);
    else { usage(); return 1; }

    return 0;
}

Результаты:

scanf: 0.63 sec
unsynced stream: 0.41 

Ответ 2

Как правило, буферизованный вход будет самым быстрым. Чем реже вы должны очистить входной буфер, тем быстрее будет вход. Для полного и очень содержательного обсуждения см. этот вопрос. Короче говоря, read() с большими размерами буфера так же быстро, как вы можете получить, поскольку он почти непосредственно поверх соответствующего системного вызова в вашей ОС.

Ответ 3

Вероятно, scanf несколько быстрее, чем использование потоков. Хотя потоки обеспечивают много безопасности типов и не требуют анализа строк формата во время выполнения, обычно это имеет преимущество, не требующее чрезмерных распределений памяти (это зависит от вашего компилятора и времени выполнения). Тем не менее, если производительность не является вашей единственной конечной целью, и вы находитесь в критическом пути, тогда вы должны действительно способствовать более безопасным (более медленным) методам.

Существует очень вкусная статья, написанная здесь Herb Sutter

http://www.gotw.ca/publications/mill19.htm

который подробно описывает производительность форматировщиков строк, таких как sscanf и lexical_cast, и какие вещи заставляют их работать медленно или быстро. Это похоже на аналогичные, возможно, на то, что может повлиять на производительность между стилем я стиля C и стилем С++. Основное различие с форматировщиками, как правило, было типом безопасности и количеством распределений памяти.