Битовый сдвиг для умножения целого числа на 10

Простой вопрос, но я не могу понять его:

Если у меня есть целое число, скажем, 12, и я выполняю над ним следующие битовые манипуляции:

int i = 12;
i = (i << 3) + (i << 1);

В итоге получается 120 (12*10). Это касается любого числа.

Может кто-нибудь кратко объяснить мне, почему это работает? (Я, очевидно, упускаю что-то довольно элементарное, когда дело доходит до битового сдвига).

Спасибо


person Jack Smith    schedule 25.05.2012    source источник
comment
Вы знаете, как работает битовый сдвиг? i << 3 — это i*(2^3) или i*8, а i << 1 — это i*(2^1) или i*2, так что если вы добавите их, вы получите i*10.   -  person Mr Lister    schedule 25.05.2012
comment
Он вам идет: en.wikipedia.org/wiki/Multiplication_algorithm#Shift_and_add   -  person Stefan    schedule 25.05.2012
comment
Также обратите внимание, что любой достойный компилятор сделает это лучше вас... Просто используйте простое умножение, и оптимизатор сделает то, что лучше для вас на текущей платформе.   -  person David Rodríguez - dribeas    schedule 25.05.2012
comment
В соответствии с комментарием Дэвида: Пожалуйста, не делайте этого, когда хотите умножить. Вы также можете разделить на степени 2, используя операции >>, а в некоторых случаях заменить & на %. Но побитовые операторы предназначены не для этого.   -  person Brian McFarland    schedule 25.05.2012


Ответы (6)


Выразить как умножение.

i = (i << 3) + (i << 1);
i = (i * 8) + (i * 2);
i = 8i + 2i
i = 10i
person Puppy    schedule 25.05.2012
comment
это действительно быстрее, чем умножение на 10? - person quintin; 10.10.2019

Вы в основном делаете:

i = i*2^3 + i*2
person lezebulon    schedule 25.05.2012

i << 3 эквивалентно i * 8. i << 1 эквивалентно i * 2.

свойство distribute сообщает нам следующее:

x = i * 10
x = i * (8 + 2)
x = 8i + 2i
person SirPentor    schedule 25.05.2012

Сдвиг влево на 3 места равен умножению на 8, сдвиг на 1 место равен умножению на 2, поэтому вы делаете

i = i * 8 + i * 2
person TheJuice    schedule 25.05.2012

Левый битовый сдвиг (обычно) такой же, как умножение на степень двойки. то есть << 1 эквивалентно *(2^1) , << 2 эквивалентно *(2^2) и так далее...

Если вы подставите это в свой пример, вы увидите, почему ваш результат умножается на 10:

int i = 12;
i = (i * 2^3) + (i * 2^1);
= { i = (i * 8) + (i * 2);}
= { i = 8i + 2i; }
= { i = 10i; }
person NominSim    schedule 25.05.2012

Перепишите битовые сдвиги как умножения на степень двойки, и все станет ясно.

person Oliver Charlesworth    schedule 25.05.2012