Вчера писал прогу по обработке изображений, и в одном месте встретилась целочисленная операция деления на 255. Как известно, процессор её выполняет достаточно медленно. А я же человек, немного фанатичный, и начал оптимизировать через операции сдвигов и битовой арифметики.
Много часов просидел, изучая картинки, вроде:
Придумывал быстро вычисляемые функции, которые как можно больше похожи на исходную. Уменьшил кол-во несовпадений до 6%, ничего страшного, если на изображении цвет пикселя немного отличается от нужного цвета. И внезапно нашел, тупое и точное решение. Закодил, грамотно запустил бэнчмарк - херня, оптимизированная версия медленней, чем исходная. Смотрю листинги, ага! в не оптимизированной версии, компилятор заменил деление на умножение на число + битовые операции. Круто, забыл, что с 2005-ой такое, майкрософтовцы молодцы:
imul eax, DWORD PTR x
mov ecx, eax
mov eax, -2139062143
imul ecx
add edx, ecx
sar edx, 7
mov eax, edx
shr eax, 31
add eax, edx
Зря потратил время? Ага, в оптимизированной функции компилятор генерирует лабуду немного, переписал - исчез условный переход и пару команд:
imul eax, DWORD PTR x
mov ecx, eax
and eax, 255
sar ecx, 8
lea eax, DWORD PTR [eax+ecx+1]
sar eax, 8
add eax, ecx
Ура, выигрыш в скорости чуть меньше чем в два раза!))
Узнал, что компилятор, при делении на 256 использует cdq, а при %256 не использует &0xff, и вообще использует много других "фич". А функции, содержащие ассемблерные вставки встраиваются неверно или с потерей производительности. Хотя в двойном цикле, типа:
for i
for j
v = i * j
значение v подсчитывает без imul, что является продвинуто. Для себя я вынес, что sar или and быстрей, чем movzx, на современных процах.