Это работает, наблюдая, что (например) y * 10 = y * 8 + y * 2
,
Это очень похоже на умножение на бумаге в школе. Например, чтобы умножить 14 x 21, мы умножаем одну цифру за раз (и сдвиг оставил место там, где это необходимо), поэтому мы добавляем 1x14 + 2 x 14 (сдвинутый налево на одну цифру).
14
x 21
----
14
280
Здесь мы делаем почти то же самое, но работаем в двоичном формате вместо десятичного. Правильное смещение не имеет ничего общего с тем, что цифры являются нечетными, и все, что нужно сделать, просто найти, какие биты в наборе заданы.
Поскольку мы сдвигаем одно право операнда, чтобы определить, установлен ли бит, мы также сдвигаем другой операнд влево, точно так же, как мы добавляем нули, чтобы сдвинуть числа влево при выполнении арифметики на бумаге в десятичной системе.
Так, рассматривая вещи в двоичном коде, мы в конечном итоге что-то вроде:
101101
x 11010
--------
1011010
+ 101101000
+ 1011010000
Если мы хотим, вместо сдвига операнда вправо, мы могли бы просто сдвинуть маску влево так, вместо того, чтобы повторно and
ИНГ с 1
, мы бы and
с 1
, затем с 2
, затем с 4
и т. д. (на самом деле, вероятно, это было бы гораздо более ощутимым образом).Однако, к лучшему или к худшему, на языке ассемблера (где обычно это делается вообще) обычно легче перемещать операнд и использовать константу для маски, чем загружать маску в регистр и при необходимости менять ее.