Блог пользователя freopen

Автор freopen, 18 месяцев назад, По-русски
Мне захотелось наконец разобраться в способах ввода-вывода в C++, какой из них быстрее и удобнее. Поэтому я написал прогу, которая проверит скорость работы основных способов ввода/вывода в C++.
Итак, разберем все тесты по порядку:

Вывод программы

Test: (printf, 10000000 ints) 2.50c
Test: (cout, 10000000 ints) 3.02c
Test: (write, 10000000 ints, 104827485 chars) 2.88c + 0.25c
Test: (scanf, 10000000 ints) 2.61c
Test: (fwrite, 10000000 ints, 104827485 chars) 2.88c + 0.26c
Test: (cin, 10000000 ints) 8.32c
Test: (printf, 100000000 chars) 1.87c
Test: (scanf, 100000000 chars) 8.44c
Test: (cout, 100000000 chars) 6.98c
Test: (cin, 100000000 chars) 12.51c
Test: (putchar, 100000000 chars) 2.26c
Test: (getchar, 100000000 chars) 1.99c
Test: (read, 100000000 chars) 0.08c + 0.57c
Test: (fread, 100000000 chars) 0.08c + 0.59c

Разбор тестов

  1. printf вывел 107 целых чисел. Относительно быстро и удобно. Вполне можно использовать.
  2. Тоже самое сделал cout. Немного медленнее, но это когда как. Иногда cout работает довольно медленно.
  3. write, как функция ostream. Работает быстро. Очень быстро. Похоже, что в основе лежит fwrite. Первое время - преобразование чисел в строку. Второе - вывод. Примечательно, что вывод куда быстрее.
  4. scanf. Работает ровно также как и printf. Сносно и удобно в использовании.
  5. fwrite. Функция из C. Работает идентично write и сравнимо с ней по сложности использования. Ну может чуть чуть сложнее.
  6. Вот и первый fail. cin считывает числа медленно. Раза в 4 медленнее, чем все остальное. Если вам в программе требуется считать миллион чисел, готовьтесь потратить на это 0.8 секунд cin-а. А возможно и больше.
  7. Переходим к символам. printf выводит символы чуть быстрее, чем числа. Видимо, из-за отсутствия необходимости преобразовывать число.
  8. А вот это стало неожиданностью. scanf на редкость медленно читает символы. Файлик был размером около 100Мб, но все равно мог бы и побыстрее.
  9. cout выводит символы медленно. В 3 раза медленнее, чем printf.
  10. cin считывает символы совсем медленно. У меня уходило 1.2 секунды на каждые 10Мб. Есть и еще один сюрприз. Он выкидывает whitespace. Даже когда считывает один символ. Про это надо не забывать. Лечится так: cin >> noskipws;
  11. putchar. Предназначен для вывода одного символа. И это у него выходит прекрасно. 
  12. getchar. Предназначен для ввода одного символа. И также он это делает очень быстро.
  13. Наконец, блочный ввод-вывод. Опять указано два параметра. Первый - время считывания. Второй - проверка на правильность считывания. Второй нужен только для сравнения. Данные предсказуемо совпадают.
  14. См. выше

Вывод

  1. Для чисел лучше использовать cin(если время не очень критично), или printf(если критично).
  2. Для символов лучше использовать getchar и putchar.
  3. Что-то мне не верится в возможность считать 100Мб данных в оперативку за 0.08 секунд. Есть версия, что файл был кеширован в оперативке. Кто знает, как это проверить и как исправить - пишите в комменты.
  4. Надо доделать тесты для строк и дробного типа. Но это уже попозже.

Тем, кто хочет проверить это на своем компьютере

Пожалуйста. Вот программа: http://pastebin.com/DpmjHF7C. Учтите, что она заменит файл temp.txt на свой, а также ей надо 100Мб свободного места и 200Мб оперативки. И пришлите мне вывод программы в комменты или в личку. Под влиянием этих данных, я возможно, изменю разбор тестов. Большое спасибо всем, кто запустит прогу у себя и пришлет мне результаты, а также тем, кто укажет мне на неточности в программе или предложит другие тесты.
 
 
 
 

 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Почти что с самого начала работы на плюсах использую scanf/printf. Удобно во многих случаях, быстро. cin/cout использую только в случае ввода/вывода string. Ну и getline иногда.
К слову, на экзамене по плюсам теория была на cin/cout, которую я успешно провалил и чуть не получил 4 =)
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну вот, а символы читает медленно. Кто же знал...
    •  
      18 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Ну, %s вроде бы тоже неплохо считывает (ТЛ не ловил еще таким образом), если дело касается чаровских массивов. Символы - тоже не ловил ТЛ со scanf. 
      •  
        18 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Попробуем еще раз. Я строки еще буду разбирать. Строки тоже десятком способов считать можно. Просто пока хочется посмотреть, есть ли интерес к теме и подправить код. А потом уже наделать еще тестов.
        •  
          18 месяцев назад, # ^ | Ответить
            Проголосовать: нравится 0 Проголосовать: не нравится
          Да про строки я уже понял =) Это так, к слову =)
 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
А fputs и fgets (и их аналоги для stdin/stdout puts и gets)? Они после fread и fwrite по скорости будут (быстрее считать строку gets'ом, чем getchar'ами).
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    В том то и дело, что строку. Со строками будут отдельные тесты. Позже. Об этом написано в посте.
    •  
      18 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Ну fread тоже не отдельные чары читает :)
      •  
        18 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        В общем то да, но я лишь утверждал, что разобрал целые и символы. Можно считать это моей наработкой на будущее :).
 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
У меня вопрос: при использовании cin символы читаются до левого пустого символа. Как узнать, какой символ был левым пустым?
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится +1 Проголосовать: не нравится
    Попробую перефразировать. cin при чтении символа пропускает все whitespace символы. Как узнать, что пропустил cin?
    Если я правильно понял вопрос, то во-первых, обычно не используют cin для такого рода задач. А во-вторых - cin >> noskipws >> c; не будет пропускать whitespace символы.
    •  
      18 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится

      Да, правильно понял) Я просто гуглил и нашёл выражение "левый пустой символ")

      Спасибо, сейчас попробую.

 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
1)
Меня вот это удивило:
Test: (printf, 100000000 chars) 1.87c
Test: (putchar, 100000000 chars) 2.26c
Почему же, интересно, printf обошел putchar...

2)
Быстрее (не медленнее) scanfа и printfа числа читает и пишет вот эта жесть:
int get_num()
{
char c;
int res=0;
do
{
c = getchar();
}
while ( c < '0' || c > '9' );
do
{
res=res*10+c-'0';
c = getchar();
}
while ( c >= '0' && c <= '9' );
return res;
}
void pr_num2( int n )
{
if ( n )
{
pr_num2( n / 10 );
putchar( n % 10 + '0' );
}
}
void pr_num( int n )
{
if ( n )
{
pr_num2( n / 10 );
putchar( n % 10 + '0' );
}
else
putchar('0');
}

Использовал её когда сдавал "на скорость" 1100 на тимусе. :)
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Но я думаю, что get_num и pr_num в реальной жизни нигде не не нужны. К тому же не являются стандартными методами. Но для статистики, возможно, интересно будет.
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Сложно сказать. Ссылку на код я дал. Анализируй или запусти у себя - посмотрим, что получится.
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится +1 Проголосовать: не нравится
    Кстати у твоих функций просто напрашивается inline в заголовке
    •  
      18 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Оу, спасибо!
      Время действительно с 0.062с уменьшилось до рекордных 0.046с.
    •  
      13 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      В чём разница функции и/или процедуры inline и без неё?
      •  
        13 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Ссылка
        Если коротко, то эту функцию компилятор будет стремиться раскрыть во всех местах вызова. Т.е. вставить внутренности функции там, где она вызывается вместо собственно вызова. Экономит время, необходимое на создание функции и на отправление ее в call stack. Эффективно, когда есть маленькая, нерекурсивная, часто вызываемая функция.
        •  
          12 месяцев назад, # ^ | Ответить
            Проголосовать: нравится 0 Проголосовать: не нравится
          Бытует мнение (и я с ним солидарен), что современные компиляторы автоматически делают инлайн всех функций, которых можно заинлайнить.
          •  
            12 месяцев назад, # ^ | Ответить
              Проголосовать: нравится 0 Проголосовать: не нравится
            а что понимается под современным компилятором?

            на моей памяти не менее двух раз был инцидент, когда написание inline позволяло получить вердикт AC вместо TL, компилятор gnu c++ 3.4.2
            •  
              12 месяцев назад, # ^ | Ответить
                Проголосовать: нравится 0 Проголосовать: не нравится
              Как утверждает эта картинка, gcc делает такую оптимизацию при -O3. Другое дело, что вряд ли в какой-то тестирующей системе стоит -O3 по умолчанию, поэтому я пожалуй погорячился.
 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Люди, пост родился из этого комментария. Можете ему написать, что этот пост существует. А то я 5 раз попробовал и не вышло. Спасибо.
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    получилось, http://codeforces.ru/blog/entry/557#comment-8883
 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
а где temp.txt взять?
  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    ммм. Зачем тебе temp.txt? Он вроде только программе нужен, но программа его и без тебя создаст. Просто если в той же директории лежит temp.txt с нужной для тебя инфой, то после запуска нужная инфа исчезнет.
 
18 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
вот характеристики моего ноута:

а вот чё вывело:

  •  
    18 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Думается мне, что у винды проблемы с непечатаемыми символами. Сейчас поправим код. Ага, вот новый.
    •  
      18 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится

      o.O

      •  
        18 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Обратите внимание, насколько putchar(11 строка) шустрее printf(7). Также обратите внимание, что cin(6) в 11 раз медленнее scanf(4). И вообще cin(6,10) тут очень тормоз, а результаты ни капли не смахивают на мои. Однако выводы по использованию остаются те же. У кого есть дополнительная информация по поводу этих (весьма странных) данных - прошу поделиться, ибо я в замешательстве.
        •  
          18 месяцев назад, # ^ | Ответить
            Проголосовать: нравится +1 Проголосовать: не нравится
          Может сделать вывод примерно таким?
          Test  1: (10000000 ints, printf) 2.50c
          Test  2: (10000000 ints, cout) 3.02c
          Test  3: (10000000 ints, write) 2.88c + 0.25c

          Тогда будет проще ссылаться на номер теста и, возможно, проще смотреть.
          •  
            18 месяцев назад, # ^ | Ответить
              Проголосовать: нравится 0 Проголосовать: не нравится
            Уже в новой версии. Кстати, попробуй сдать 1100 за 0.031. Там есть несколько очень забавных моментов, которые красиво решаются.
            •  
              18 месяцев назад, # ^ | Ответить
                Проголосовать: нравится 0 Проголосовать: не нравится
              Сейчас спать надо.
              А сдать обязательно попробую. :)
 
18 месяцев назад, # | Ответить
  Проголосовать: нравится +1 Проголосовать: не нравится
Если возможно, может ли администрация показать соответствующие циферки на серверах codeforces, чтобы можно было понять, с какой скоростью осуществляется считывание и запись данных?
 
17 месяцев назад, # | Ответить
  Проголосовать: нравится +1 Проголосовать: не нравится
хотелось бы задать пару вопросов, хотя возможно не в подходящий пост...
1) как в С++ перевести коретку на следующую строку? в пасцале это можно сделать readln(), а вот в С++ не знаю(((
2) как в С++ прочитать строку интов? в пасцале это можно записать так : while not eoln do read();

за ранее благодарю!

  •  
    17 месяцев назад, # ^ | Ответить
      Проголосовать: нравится -3 Проголосовать: не нравится
    1) cout << '\n'; или можно cout << std::endl;
    2) while (cin >> x) {}
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится -6 Проголосовать: не нравится
      ты с паскалем или делфой знаком немного хоть???
      1) вообще бред, в С++ cin эквивалентен паскалевскому read().
      я же прошу, вот тебе даже такой пример, у тебя на входе дана симметрическая матрица
      1 2 0
      2 3 7
      0 7 9
      а я прошу как считать только :
      1
      2 3
      0 7 9
      т.к. все символы мне нет смысла читать, если сказано что матрица симметрическая.

      2) ты написал пока не конец файла!!! в паскале это эквивалентно while not eof !!!!
      а я прошу пока не конец строки (((

      ЗЫ так в принципе и ожидал что мне это ответят(((
      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится +1 Проголосовать: не нравится
        сорри, невнимательно прочитал твой пост.. И думаю не стоит сразу так резко на это реагировать.
      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        вообще, тебе это скорее всего надо для того, чтобы писать лабы по ВМА с симметрическими матрицами.. но там они и будут введены как треугольные. В противном случае в С++ ничего такого нету, считывай строку - из неё выдирай инты.
        •  
          17 месяцев назад, # ^ | Ответить
            Проголосовать: нравится 0 Проголосовать: не нравится
          ))) вма это ты конечно загнул)))
          просто год назад задачу встретил там надо матрицу считать именно так как я выше написал, иначе ТЛ схватишь((( вот тогда на пасе я написал, а на плюсах не смог((( вот поэтому и попросил помощи...
          ЗЫ извини если что не так, в любом случае спасибо что откликнулся.
  •  
    17 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Не знаю, как надо "правильно", но я в таких случаях делаю так:
    1) scanf("\n");

    2)     string str;
    getline(cin, str);
    stringstream ss(str);
    int elem;
    while (ss >> elem) {
    DoSmthWith(elem);
    }
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      а нельзя ли читать инты не выделяя их из строки? просто в таком случае будет быстрее читать посимвольно и выделять инты. или я не прав?
      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Считать строку быстрее, потом из неё sscanf'ом считывать всё что хочешь в любом формате. Перевести каретку можно, например, с помощью gets, но в любом случае надо дочитать строку до конца(и в паскале тоже), чтобы узнать где её конец:) Так что от считывания всего ввода не убежишь.
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      1) Так не стоит делать. Смотри мой ответ снизу.
  •  
    17 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    1)
    char buffer[100500];
    gets(buffer);

    НЕ РЕКОМЕНДУЕТСЯ писать scanf("\n"); так как он прочитает все пробельные символы (т.е. может сразу несколько пустых строчек зохавать).

    2)

    while ( scanf("%d", &n) == 1 ) {
        ...
    }

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

    ПОЭТОМУ не стоит писать так:
    while ( scanf("%d", &n) )

    Много раз сам валился на этом. :)
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      1) Спасибо, не знал. В олимпиадных задачах чаще всего нужно просто пропустить все пробелы и переводы строк до нужных данных. Там scanf("\n") работает.

      2) while ( scanf("%d", &n) == 1 ) { ... } 
      читает все числа из файла, а тут нужно одну строчку. Лучше всего тут прочитать сначала строку, а потом распарсить sscanf-ом или stringstream-ом. 

      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        1) Я раньше тоже всегда так читал. :)
        А потом в Сазанке у нас упала программа вот с таким тестом.
        3
                       
        a b c
        d e f

        scanf("\n") прочитал аж до начала третей строчки. Потом три gets() в цикле выдали 3ю, 4ю и 4ю (!) строчки у нас был стабильно WA.

        2) Вот теперь я неправильно прочитал))
        Привожу рабочий код sscanf (спасибо Foton за по сути его написание :)

        char buffer[10000], *iter, s[1000];

        int main()

        {

            gets(buffer);

            iter = buffer;

            while ( *iter == ' ' )

                    iter++;

            while ( sscanf(iter, "%s", &s) == 1 )

            {

                sscanf(s, "%d", &a);

                printf("%d ", a);

                iter += strlen(s);

                    while ( *iter == ' ' )

                        iter++;

            }

            return 0;

        }

        •  
          17 месяцев назад, # ^ | Ответить
            Проголосовать: нравится 0 Проголосовать: не нравится
          Если туда сверху прикрутить

          #include <cstdio>
          #include <string.h>
          int a;

          то оно скомпилируется.
 
17 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится

вот:

  •  
    17 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    А что это?
  •  
    17 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Здорово. А можно это же самое в release-mode? Кстати, обратите внимание, как здраво не рулит cin на интах на этом компе.
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится

      а что такое release mode, тут немного погуглил(оказывается есть debug mode) нашел на англ яз с которым у меня не сложились отношения, можно в двух слова в чем отличие?

      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        debug mode - скомпилировать прогу с отладочной информацией. В exe войдет исходный текст проги, способ ее остановить на любой строчке, проверка разных вещей типа выхода за границы массивов и т.п.
        release mode - скомпилировать программу соптимизировав ее для полноценной работы.

        Проги на серверах чаще тестируются в release mode. Поэтому он нам более интересен.
      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Хотел сказать, но забыл. Этот mode ставится в настройках среды обычно. Например в minGW Studio это называется "Set active configuration".
        •  
          17 месяцев назад, # ^ | Ответить
            Проголосовать: нравится 0 Проголосовать: не нравится

          спс за инфу

          у меня codeblocks 8.02 не нашел там ничего такого:(

 
17 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится

Test: (printf, 10000000 ints) 11.34c

Test: (cout, 10000000 ints) 27.69c

Test: (write, 10000000 ints, 56609008 chars) 6.67c + 1.55c

Test: (scanf, 10000000 ints) 7.17c

Test: (fwrite, 10000000 ints, 56609008 chars) 6.67c + 1.31c

Test: (cin, 10000000 ints) 31.34c

Test: (printf, 100000000 chars) 41.64c

Test: (scanf, 100000000 chars) 52.09c

Test: (cout, 100000000 chars) 25.36c

Test: (cin, 100000000 chars) 69.89c

Test: (putchar, 100000000 chars) 14.25c

Test: (getchar, 100000000 chars) 18.23c

Test: (read, 100000000 chars) 1.55c + 0.53c

Test: (fread, 100000000 chars) 1.17c + 0.47c

  •  
    17 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Спасибо. Как у тебя все небыстро. scanf и cin не рулят на char-ах
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Может сделать так:
      scanf:
      всё про сканф

      printf:
      всё про принтф

      cin:
      ...

      cout:
      ...

      gectchar:
      ...

      putchar:
      ...

      gets:
      ...

      puts:
      ...

      read:
      ...

      fread:
      ...

      И одинаковые тесты (по возможности) для каждого метода ввода и вывода.

      А вообще да, у меня медлене машинка.
      •  
        17 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Почитай код и поймешь, где ты не прав. Все будет, но чуть позже
    •  
      17 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Я читал немного. :) Можно будет поразбираться.
      Кстати, это release...
 
16 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Проект, на котором тестируется скорость различных языков на различных системах: http://shootout.alioth.debian.org/
 
16 месяцев назад, # | Ответить
Правка 5   Проголосовать: нравится 0 Проголосовать: не нравится
g++ iotest.cpp -o iotest

./iotest

  • Test: (printf, 10000000 ints) 1.71c
  • Test: (cout, 10000000 ints) 2.30c
  • Test: (write, 10000000 ints, 104827485 chars) 2.16c + 0.18c
  • Test: (scanf, 10000000 ints) 2.11c
  • Test: (fwrite, 10000000 ints, 104827485 chars) 2.16c + 0.17c
  • Test: (cin, 10000000 ints) 7.27c
  • Test: (printf, 100000000 chars) 1.63c
  • Test: (scanf, 100000000 chars) 5.45c
  • Test: (cout, 100000000 chars) 7.10c
  • Test: (cin, 100000000 chars) 9.93c
  • Test: (putchar, 100000000 chars) 1.64c
  • Test: (getchar, 100000000 chars) 1.33c
  • Test: (read, 100000000 chars) 0.08c + 0.28c
  • Test: (fread, 100000000 chars) 0.07c + 0.28c

g++ --version

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 
13 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Хорошо было бы графиком оформить сравнение.
Хоть в экселе, чтоб наглядней было . . .
 
13 месяцев назад, # | Ответить
  Проголосовать: нравится +3 Проголосовать: не нравится
советаю функцию scanf("%d", &var) писать так:

var = get();

inline int get()
{
    for (C = getchar(); (C < 48 || C > 57) && C != '-'; C = getchar());
    if (C == '-')
        neg = 1,
        C = getchar();
    else
        neg = 0;
    x = 0;
    for (; 47 < C && C < 58; C = getchar())
        x = x*10 + C - 48;
    if (neg)
        return -x;
    else
        return x;
}


Функция get() читает по одному символу и преобразовывает эти символы в число.

Тэстил. Заметно ускоряет время.
  •  
    13 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Почитай вот эту ветку. У меня было что-то подобное.
  •  
    13 месяцев назад, # ^ | Ответить
      Проголосовать: нравится +3 Проголосовать: не нравится

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

    •  
      13 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Авторы олимпиадных задач все-таки разные бывают и расслабляться не стоит в любом случае. А такие трюки иногда помогают протолкнуть n^2 при n=10000, если нужен nlogn. Редко, правда. Но вот на codeforces люди начинают выть даже если задачи незначительно отличаются от среднестатистической задачи. И потом, кто сказал, что знание тонкостей языка бесполезно. Оно может помочь в задачах на оптимизацию, в которых не надо особо оптимизировать ввод.
 
12 месяцев назад, # | Ответить
Правка 2   Проголосовать: нравится 0 Проголосовать: не нравится
А вот эту штуку не пробовал? http://codeforces.ru/blog/entry/10
Хорошо бы и с ней протестить cin, cout . . .
 
12 месяцев назад, # | Ответить
Правка 4   Проголосовать: нравится 0 Проголосовать: не нравится
Ubuntu 10.04

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

BY YATSUKOYIN ON THE 23RD OF JAN 2011 03:27:24 AMDOWNLOAD | RAW | EMBED | REPORT
  1. Test: (printf, 10000000 ints) 2.49c
  2. Test: (cout, 10000000 ints) 3.44c
  3. Test: (write, 10000000 ints, 104827485 chars) 3.24c + 0.21c
  4. Test: (scanf, 10000000 ints) 3.08c
  5. Test: (fwrite, 10000000 ints, 104827485 chars) 3.24c + 0.21c
  6. Test: (cin, 10000000 ints) 10.56c
  7. Test: (printf, 100000000 chars) 2.35c
  8. Test: (scanf, 100000000 chars) 7.64c
  9. Test: (cout, 100000000 chars) 9.65c
  10. Test: (cin, 100000000 chars) 13.88c
  11. Test: (putchar, 100000000 chars) 2.42c
  12. Test: (getchar, 100000000 chars) 1.94c
  13. Test: (read, 100000000 chars) 0.11c + 0.40c
  14. Test: (fread100000000 chars) 0.12c + 0.39c
 
12 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Вопрос по С++ или даже по Visual Studio, но относится к ТопКодеру.

Писал долго SRMы в NetBeans на Java и был доволен, но сегодня меня Java по некоторым причинам разочаровала и не в первый раз, так что я решил вернуться к С++.

Теперь вопрос: как сделать, чтобы в режиме отладки окно консоли не закрывалось мгновенно? Я использую плагин moj, но не знаю, как его модифицировать, чтоб вписать туда что-то типа system("pause");

Второй вопрос. Где нужно поставить галочку в настройках, если это вообще возможно, чтобы закрывающиеся скобки (и обычные, и фигурные) добавлялись автоматически? Особо хочется добавления фигурных скобок - в NetBeans привык и теперь совсем непривычно их самому ставить.

Третий вопрос. Какой самый правильный способ перевода строки в число и обратно и чтения чисел из строки?
  •  
    12 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну есть stringstream, он действует и туда и обратно, правда он тормознутый зараза... Перевод из строки в число если в 32-битный то atol(atoi), 64-битный я ручками перевожу если stringstream в ТЛ хочет уйти.
    Действует stringstream так:
    #include<sstream>
    ...
    int n; string s;
    cin >>s;
    stringstream ss;
    ss <<s;
    ss>>n;
    ну и в обратную точно так же:
    ss<<n;
    ss>>s;
    •  
      12 месяцев назад, # ^ | Ответить
        Проголосовать: нравится 0 Проголосовать: не нравится
      Спасибо.
      А если в строке всякие там запятые, то мне надо эти чары считывать?
      •  
        12 месяцев назад, # ^ | Ответить
          Проголосовать: нравится 0 Проголосовать: не нравится
        Не понял насчет запятых. Дабловое число что ли?
        •  
          12 месяцев назад, # ^ | Ответить
            Проголосовать: нравится 0 Проголосовать: не нравится
          Нет.
          Я же сказал, что мне эта штука нужна для ТопКодера, а там частенько данные задают в виде строки, в которой числа разделены чаще всего пробелами, но, бывает, и запятыми.
          •  
            12 месяцев назад, # ^ | Ответить
              Проголосовать: нравится 0 Проголосовать: не нравится
            заменяешь знаки препинания на пробелы)
          •  
            12 месяцев назад, # ^ | Ответить
              Проголосовать: нравится 0 Проголосовать: не нравится
            strtok и по разделителям "., -" (перечень разделителей)
            (если Вы об этом)
  •  
    12 месяцев назад, # ^ | Ответить
    Правка 2   Проголосовать: нравится 0 Проголосовать: не нравится

    1) Чтение чисел из строки без тормозов:

    char str[mxx]="1 2";

    sscanf(str,"%d %d",&n,&m);

    2) Строка в число для 64-битных чисел без тормозов:

    char str[mxx]="12345678910111213";

    long long big;

    sscanf(str,"%I64d",&big);

    Про консоль не очень понял. Если в режиме отладки, то ставишь breakpoint на последний return 0. А если просто запустить и посмотреть что вывелось на консоль, то как вариант написать _getch() //#include <conio.h> . Не забыть его потом убрать!!! :)

    •  
      12 месяцев назад, # ^ | Ответить
      Правка 2   Проголосовать: нравится 0 Проголосовать: не нравится
      Проблема была с консолью в том, чтобы мне этот getch() или system("pause") не писать вручную каждый раз. Кажется, разобрался, как поместить это в плагин.

      Ладно, и sscanf как-нибудь попробую.
  •  
    12 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Чтение чисел... Ну можно int n;cin>>n, scanf("%d",&n) и его разновидности. Лучше все-таки сканф, т.к. можно чтобы кое-какие символы пропускал-ставишь эти символы после %d
  •  
    12 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    как сделать, чтобы в режиме отладки окно консоли не закрывалось мгновенно? Я использую плагин moj, но не знаю, как его модифицировать, чтоб вписать туда что-то типа system("pause");

    Ctrl + F5?
  •  
    8 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    1) Используй "Win32 Console Application" вместо "Empty Project" при создании проекта. Поставь галку в "Additional options->Empty project" чтобы созданный консольный проект был чистым. 
 
12 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
zaminisuyte menya plz!
 
12 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
спасибо за статью. помогла уложить в ограничения.
  •  
    12 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Рад, что моя статья оказалась полезна. Зачем вы написали в английский интерфейс?
 
9 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Какой rand() на твоей машине? В Windows и Linux они отличаются!
  •  
    9 месяцев назад, # ^ | Ответить
      Проголосовать: нравится 0 Проголосовать: не нравится
    Привет, Миша. А то ты не знаешь :). Linux, я тогда не подумал сделать универсальный rand.
 
9 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Для создания временного файла лучше использовать tmpfile (http://cplusplus.com/reference/clibrary/cstdio/tmpfile/) или tmpnam (http://cplusplus.com/reference/clibrary/cstdio/tmpnam/). Также можно временный файл удалить в конце или через atexit.
 
9 месяцев назад, # | Ответить
Правка 3   Проголосовать: нравится 0 Проголосовать: не нравится
> Вот и первый fail. cin считывает числа медленно. Раза в 4 медленнее, чем все остальное. Если вам в программе требуется считать миллион чисел, готовьтесь потратить на это 0.8 секунд cin-а. А возможно и больше.

> cin считывает символы совсем медленно. У меня уходило 1.2 секунды на каждые 10Мб.

Это потому что вы неправильно используете потоки для считывания... Попробуйте так:

void test_ifstream_int() {
	int cur = clock();
	ifstream ifs("temp.txt", ifstream::in);
	for(int i = 0; i < N; i++) {
		int t;
		ifs >> t;
		if(t != a[i]) {
			fprintf(stderr, "Fail with ifstream\n");
			exit(1);
		}
	}
	ifs.close();
	fprintf(stderr, "Test: (ifstream, %d ints) %.2lfc\n", N, (clock() - cur + .0) / CLOCKS_PER_SEC);
}

ну и, соответственно так:
void test_ifstream_char() {
	int cur = clock();
	ifstream ifs("temp.txt", ifstream::in);
	for(int i = 0; i < N; i++) {
		char t;
		ifs >> t;
		if(t != s[i]) {
			fprintf(stderr, "Fail with ifstream\n");
			exit(1);
		}
	}
	ifs.close();
	fprintf(stderr, "Test: (ifstream, %d chars) %.2lfc\n", NC, (clock() - cur + .0) / CLOCKS_PER_SEC);
}

Результат:
Test: (cin, 10000000 ints) 6.04c
Test: (ifstream, 10000000 ints) 2.08c
Test: (cin, 100000000 chars) 9.43c
Test: (ifstream, 100000000 chars) 0.19c

Просто использовать небуферизированный ввод для чтения 100МБ - это как-то не по-программистски. ;)



> Есть и еще один сюрприз. Он выкидывает whitespace. Даже когда считывает один символ. Про это надо не забывать. Лечится так: cin >> noskipws;

Может лечится гораздо проще... cin.get(t); вместо cin >> t; - заодно и производительность вырастает.
  •  
    8 месяцев назад, # ^ | Ответить
      Проголосовать: нравится -1 Проголосовать: не нравится
    Гораздо проще - понятие растяжимое. К примеру, у меня в программе символ считывается в 30-40 местах, тогда уж лучше noskipws, чем везде переделывать.
 
8 месяцев назад, # | Ответить
  Проголосовать: нравится +1 Проголосовать: не нравится
А как в timus 1000 задачу за 0.001 сдают ? Особый ввод вывод ?
  •  
    8 месяцев назад, # ^ | Ответить
      Проголосовать: нравится +4 Проголосовать: не нравится
    Раньше было можно, так как программы, работающие неподсчётно быстро, получали время 0.001 (а теперь минимум - 0.015)
 
8 месяцев назад, # | Ответить
  Проголосовать: нравится +1 Проголосовать: не нравится
После добавления в начало main() шаманства для ускорения потоков -- "std::ios_base::sync_with_stdio(false);", программа начала падать:
===
Test: (printf, 10000000 ints) 2.45c
Test: (cout, 10000000 ints) 3.08c
Test: (write, 10000000 ints, 104827485 chars) 3.13c + 0.31c
Fail with scanf
===
Строка компиляции: g++ -Wall q.cpp -o q
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Никто не в курсе почему такое происходит и как с этим бороться?
Если закомментить падающие методы, то, как и ожидалось, потоки показывают примерно такую же производительность, что и scanf/printf.
  •  
    8 месяцев назад, # ^ | Ответить
      Проголосовать: нравится +1 Проголосовать: не нравится
    Вопрос снят.
    std::ios_base::sync_with_stdio(false), как видно из названия, отключает синхронизацию со стандартными потоками.
    С другой стороны printf() у меня работает нормально даже с отключенной синхронизацией.
    В итоге, чтобы тест прошел с
    std::ios_base::sync_with_stdio(false), пришлось закомментить test_scanf_int(); и test_cout_char();
    Есть предположения почему?
    Главный вопрос: как безопасно ускорять потоки, чтобы как минимум можно было использовать printf().
    •  
      8 месяцев назад, # ^ | Ответить
        Проголосовать: нравится -2 Проголосовать: не нравится
      М.б. написать свой cin?
    •  
      8 месяцев назад, # ^ | Ответить
        Проголосовать: нравится -2 Проголосовать: не нравится
      Кстати вопрос остается в силе, т.к. мне нифига не понятно. Подключал файл я через freopen, так что scanf должен был выжить. Пофиг на синхронизацию, я их вместе не использую.
      •  
        8 месяцев назад, # ^ | Ответить
          Проголосовать: нравится -4 Проголосовать: не нравится
        freopen подключает файлы через freopen. Хотя, с другой-то стороны, через что еще ему подключать их?
    •  
      8 месяцев назад, # ^ | Ответить
      Правка 2   Проголосовать: нравится -1 Проголосовать: не нравится

      Вот, нашел кое-что: http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/ - здесь используется модуль stdarg, создается функция подобная printf и параметры передаются в perror. Если передать на cout - получится искомый метод.
    •  
      8 месяцев назад, # ^ | Ответить
      Правка 2   Проголосовать: нравится 0 Проголосовать: не нравится

      ну если вместо freopen использовать fopen и fstream, то всё нормально работает.
      http://pastie.org/2102887
 
7 месяцев назад, # | Ответить
  Проголосовать: нравится 0 Проголосовать: не нравится
Много и трудно мне пришлось бороться за производительность C/C++ ных программ на разных платформах, начиная от тех у которых аж по 1кб оперативки... И я одно скажу - обязательно нужно указывать компилятор, указывать опции оптимизации с которыми выполнялась проверка... Ну и всё равно интерес в этом сравнении останется довольно академическим... ;-)
  •  
    7 месяцев назад, # ^ | Ответить
      Проголосовать: нравится -5 Проголосовать: не нравится
    Академическим, как и многое на этом сайте.