Comments 17
Была у меня мысль вернуться к этой задаче, повода не было. Теперь есть :)
И кстати, для замеров лучше использовать time
, это точнее
ну и вот: https://habr.com/ru/post/682332/
FizzBuzz in C, Ansi-style
Я так и не смог понять, что имеется в виду под "ansi style". Автор местами использует фичи C99, но при этом валит объявления переменных в одну кучу в начале функции и избегает инициализации... С const тоже винегрет: где-то есть, где-то нет.
Вот только 0,001 секунд без fwirte
достигается из-за того, что умный компилятор вырезает вообще все вычисления, потому что их результат никак не используется.
Одно принципиальное замечание - убирать строки с fwrite
из программы нельзя, потому что в этом случае оптимизатор может смело выкинуть всю работу с буфером, то есть практически весь код. Отсюда и получается магический результат в 0.001 сек. Сениоры такое знают ;)
Уже выше написали
И оставлять нельзя, это может повлиять на замеры времени. Я обычно помещаю fwrite в заведомо невыполнимую ветвь кода, чтонить типа
if argv[1] == "5" && result.size() == 100 {
fwrite(...)
}
Я просто перенаправлял вывод в /dev/null
, это конечно чуть добавляет, но незначительно.
Думаю, что вполне можно допустить, что при выводе в /dev/null
все использованное программой время - вычисления, ну еще и немного времени kernel
'а при многопоточного варианта, но это тоже можно считать в общие расходы программы (без I/O)
Блин, ну и говнокод о_О
Ну если оптимизировать, то должна быть поддержка многопоточных вычислений. Иначе хорошо читаемый код сеньора при добавлении пары операторов побьёт этот нечитаемый код даже по производительности.
Вот пожалуйста, тут и условия и бенчмарки и результаты вплоть до 150х от наивного.
Это немного другая задача. На codegolf FizzBuzz бесконечный, а тут ограничен миллиардом, что позволяет дополнительные оптимизации
Там немного другая оптимизация. Просто вывод fwrite по 30 строк в миллиарде требует почти 1.5 сек. Многопоточность там разрешена и достаточно 3 потоков, чтобы получить максимальную скорость вывода.
Если там что есть быстрее (20G/sec у xiver77), то это уже оптимизация ввода/вывода. Ну и алгоритмически неинтересна. В этой статье собственно скорость не главное. Тут вся хитрость в алгоритме.
Даже если провести очевидные оптимизации сеньорского кода - использовать в одной команде деление с остатком (ассемблерный код, наверно) и убрать деление до 0 в myitoa и найти другой критерий останова.
do {
*--cur = number % 10 + '0';
number /= 10;
} while (number != 0);
то все равно мой код будет быстрее - в нем для получения каждого байта кода вывода используется "+1" или "+3" и ">9", что гораздо быстрее деления на 10.
Итак, чтобы победить этот мой изящный говнокод, сеньорам нужно придумать что-то умное или хитрое. Просто так парой операторов дело провернуть не получится.
FizzBuzz по-пенсионерски