Итак, у нас есть какая-то задачка. Качество решения определяется временем выполнения: меньше - лучше. В первую очередь нам нужен рациональный алгоритм, но не только. Процесс работы программы зачастую сильно затягивается из-за "узких мест". Типичный случай - простой процессора в ожидании результата обращения к памяти. С этим можно бороться по следующей аналогии.
Представьте, что вы делаете ручную работу, сидя за просторным деревянным столом. Инструменты и материалы разложены по полкам в шкафу в 3-х метрах от вас. Если всякий раз выкладывать ту или иную вещь из рук на полку и брать с полки, большая часть времени уйдет на хождение от стула к шкафу и обратно. Умный человек довольно скоро додумается разместить активно используемые инструменты прямо на столе, чтоб они были под рукой.
Вернемся к компьютеру. В компьютере, по грубой аналогии, роль стола играет процессор, роль шкафа - оперативная память, а жесткий диск, который нас, впрочем, не интересует, представляет большой склад в отдаленном помещении. Нас интересуют регистры - это такая штука в процессоре, которая в нашем случае играет роль места "под рукой" для размещения активно используемых вещей, в т.ч. и тех, что обрабатываются в текущий момент. Не буду вдаваться в подробности, какое особое назначение у RAX, RBX, RCX, RDX, RSI, RDI.. Скажу лишь, что они всегда используются, в худшем случае (тупой компилятор) только для счетчика комманд, указателя стека и прочих технически важных вещей, а также для передачи некоторых аргументов функции, возвращаемого значения функции и для переменных, над которыми идет операция в текущий момент, после чего каждый раз производится перезапись в память. На языке высокого уровня этого не видно, видны лишь имена переменных, а реальный (машинный) код создается компилятором. Assembly же, где соотношение того, что вы пишете, и того, что получится - один к одному, отпускает полный контроль под ваши руки.
Перейдем к делу. Возьмем простенький итерационный алгоритм нахождения n-го числа Фибоначчи.
Если запустить цикл while на несколько миллирадов итераций, такое количество обращений к памяти (f,f1,f2) займет немало времени. Можно написать функцию fibo(n) на ASM.
Но подобная экзотика не всем по вкусу. К счастью, такая прекрасная вещь, как C/++, позволяет во многих случаях обходиться и без Assembly. Можно "попросить" компилятор держать, по возможности, те или иные переменные по возможности держал в регистрах. Делается это очень просто: перед объявлением переменной пишется ключевое слово register.
Но надо еще все протестировать. Запустим это дело на 4 миллиарда. С такими входными данными, разумеется, ни о каком корректном результате речи не идет, но главное, чтоб не вылетало (благо не Java, под 64 бита срежет и промолчит) и чтоб обе memslow и regfast дали одинаковый результат, этого более чем достаточно для честной проверки быстродействия.
Скриншот говорит сам за себя. 5-кратная разница в результате. А вот разница в причине такого результата.
Выделена та часть, где вводятся f, f1, f2.
Первое - медленный вариант, последнее - быстрый. Обратите внимание, что в последнем случае за весь цикл (все что между jmp и jne) - ни разу не обращаемся к памяти.
Ассемблерную часть изложенной инфы не обязательно всем понимать, достаточно было узнать про register-фичу языка C. Не вижу смысла расписывать ASM, кто шарит тот шарит, а кто не шарит, но хочет, тому могу посоветовать хорошую книжку PC Assembly Language чувака по имени Paul A. Carter (ссылку оставлю в комментах).
Сомневаюсь, что будут плюсы, поскольку не занимаюсь регулярно постами на какую-либо тематику, и вообще сам учусь, но чувствую необходимость где-то это зафиксировать, чтоб хоть сокурснику в удобном виде (ссылка Pikabu) кинуть. Грубо говоря, воспользовался сайтом в качестве удобного средства оформления информации с такими ништяками, как картинки и хранение в сети. Да простят меня за это.
Гавнокод мой - тег моё.