Побитовые операторы


Прямой, обратный и дополнительный код числа
http://www.reshinfo.com/dopolnit_code.php

Перевод в разные системы счислений

Перевести число из десятичной в другую систему счисления позволяет функция .toString(n); где n - основание системы счисления

    (7).toString(2);      // "111"

Перевод числа в десятичную систему счисления - функция parseInt("...", m), где m указывает из какой системы осуществляется перевод в десятичную

    parseInt(111, 2);   // 7

Перевести число из любой системы m в любую систему n позволяет комбинация этих двух функций

    parseInt("...", m).toString(n); 

Например, переведём 111 из двоичной системы в троичную

    parseInt(111, 2).toString(3); // 21  

Функция .toString(n); переводит только числа и возвращает строку, функция parseInt("...", m); принимает и числа и строки и возвращает число.

Побитовые операторы

ОператорИспользование Описание
Побитовое И (AND) a & b Ставит 1 на бит результата, для которого соответствующие биты операндов равны 1.
Побитовое ИЛИ (OR) a | b Ставит 1 на бит результата, для которого хотя бы один из соответствующих битов операндов равен 1.
Побитовое исключающее ИЛИ (XOR) a ^ b Ставит 1 на бит результата, для которого только один из соответствующих битов операндов равен 1 (но не оба).
Побитовое НЕ (NOT) ~a Заменяет каждый бит операнда на противоположный.
Левый сдвиг `a << b` Сдвигает двоичное представление a на b битов влево, добавляя справа нули.
Правый сдвиг, переносящий знак `a >> b` Сдвигает двоичное представление a на b битов вправо, отбрасывая сдвигаемые биты.
Правый сдвиг с заполнением нулями `a >>> b` Сдвигает двоичное представление a на b битов вправо, отбрасывая сдвигаемые биты и добавляя нули слева.

Зачем нужны побитовые операторы?

Ну, во-первых. они работают быстрее. Намного быстрее. В разы.
Битовый сдвиг работает быстрее умножения, html5 canvas использует побитовые операторы.

Округление при помощи побитового ИЛИ работает вдвое шустрее Math.floor http://javascript.ru/bitwise-operators


    ( 100 / 3 ) | 0; // 33

А нужны ли тут скобки? Смотрим приоритет операторов деление - 14, побитовое ИЛИ - 7.
То есть деление и так выполнится раньше, скобки не нужны для управления последовательностью действий, но, возможно, улучшают читабельность кода, особенно если таблицу приоритетов наизусть не выучил.


& (Побитовое И)

14 & 9 // 8

14
8 + 4 + 2
1110

9
8 + 0 + 0 +1
1001

1110
1001
1000 – 8
________________

| (Побитовое ИЛИ)

14 | 9 // 15

1110
1001

1111 – 15

^ (Исключающее ИЛИ)

14 ^ 9 // 7

1110
1001

0111 – 7

7 ^ 9 // 14

0111
1001

1110 - 14

В общем виде справедлива формула

    a ^ b ^ b == a

Это позволяет использовать исключающее ИЛИ для шифрования.
Если предположить, что а - данные, которые нужно зашифровать, а b - ключ, который есть у обеих сторон, то дважды применив исключающее ИЛИ получим исходный текст.

Для чего можно использовать побитовые операторы
1) округление чисел

    ~~6.354; // 6
    6.354 ^ 0;  // 6

2) Быстрое умножение или деление на 2 в степени n, которое выполняется в один такт.

     9 >> 1 // 4, потому что сдвинуть на один бит вправо всё равно что разделить на два в первой степени, а потом округлить до целого
    4 << 3 //  32 потому что 4 * 2^3 = 4 * 8 = 32

3) проверка на -1

Чтобы сменить знак числа на противоположный нужно изменить каждый его бит на противоположный (побитовое НЕ) и прибавить единицу.

    ~n + 1 = -n , откуда ~ n = -n + 1

Таким образом ~n = 0 только если n = -1.

Это значение можно добавить в условие if ( ~n ) { .. }, которое будет выполняться только если n не равно -1. Такая возможность полезна для тех функций, которые возвращают -1 в случае отсутствия результата. Например, indexOf()  возвращает первое вхождение подстроки в строку, или -1.

    str.indexOf("подстрока") 
    "ля-ля-ля".indexOf("оля")  // -1


 4) проверка чётное число или нечётное
В двоичном представлении нечётных чисел последняя цифра справа всегда единица. Применение побитового И с единицей для нечётных чисел даёт 1, для чётных 0:

    11 & 1 // 1
    12 & 1 // 0

5) c помощью исключающего ИЛИ ^ можно поменять значения двух переменных (имеющих одинаковый тип данных) без использования временной переменной.

    function swapper(a, b) {
        a = b ^ a; // заменяет временную переменную, которая не равна ни а, ни b, но из которой их легко получить
        b = a ^ b; // получается b = b ^ a ^ b => а
        a = a ^ b;  // получается a = b ^ a ^ a => b
        return [a, b]
    }

6) побитовое НЕ плюс единица меняют знак числа

    ~n + 1 // -n


7) конечно же побитовые маски, когда у каждого объекта есть куча свойств (но не больше 32, числа ведь используются 32-битные) и нужно их определить или на них повлиять

Дополнительно: Хитрости с битовыми операциями

Дополнено

В обсуждении задали вопрос
Что быстрее работает: a^0 или ~~a?

Проверить скорость работы можно на сайте https://jsperf.com/bitwise-operators-speed  (это уже созданный тест)

Его результаты


То есть ни о каких выигрышах в 65% или 36% речи не идёт. Разница в скорости составляет доли процента и зависит от браузера. Но ~~a всё-таки немного быстрее.

UPD Терплю это "безобразие" уже несколько страниц, но сил уже не осталось. Не нужно проверять число на чётность с помощью '%'. Эта операция занимает довольно много тактов процессора. Гораздо проще (и в смысле читаемости тоже) и уж точно быстрее использовать побитовое и '&'. Например так.

if (  n & 1) // число нечётное 

источник