Что такое побитовые операторы?

Я тот, кто пишет код просто для удовольствия и в действительности не углубляется в него ни в академической, ни в профессиональной обстановке, поэтому такие вещи, как эти побитовые операторы, действительно ускользают от меня.

Я читал статью о JavaScript, который, очевидно, поддерживает побитовые операции. Я продолжаю видеть эту операцию упомянутой местами, и я попытался прочитать, чтобы выяснить, что именно, но я просто, кажется, не понимаю ее вообще. Так что они? Четкие примеры были бы великолепны!:D

Еще несколько вопросов - каковы практические применения побитовых операций? Когда вы могли бы использовать их?

10 ответов

Решение

Поскольку никто не затронул тему, почему они полезны:

Я часто использую побитовые операции при работе с флагами. Например, если вы хотите передать серию флагов операции (скажем, File.Open с включенными режимами чтения и записи), вы можете передать их как одно значение. Это достигается назначением каждому возможному флагу своего собственного бита в наборе битов (байтов, коротких, целых или длинных). Например:

 Read: 00000001
Write: 00000010

Таким образом, если вы хотите передать чтение и запись, вы должны передать (READ | WRITE), который затем объединит их в

00000011

Который затем может быть расшифрован на другом конце, как:

if ((flag & Read) != 0) { //...

который проверяет

00000011 &
00000001

который возвращается

00000001

который не равен 0, поэтому флаг указывает READ.

Вы можете использовать XOR для переключения различных битов. Я использовал это при использовании флага для указания направленных входов (вверх, вниз, влево, вправо). Например, если спрайт движется горизонтально, и я хочу, чтобы он развернулся:

     Up: 00000001
   Down: 00000010
   Left: 00000100
  Right: 00001000
Current: 00000100

Я просто XOR текущее значение с (LEFT | RIGHT), который в этом случае выключит LEFT и RIGHT.

Сдвиг битов полезен в нескольких случаях.

x << y

такой же как

х * 2 года

если вам нужно быстро умножить на степень два, но следите за смещением 1 бита в верхний бит - это делает число отрицательным, если оно не подписано. Это также полезно при работе с данными разных размеров. Например, чтение целого числа из четырех байтов:

int val = (A << 24) | (B << 16) | (C << 8) | D;

Предполагая, что A является наиболее значимым байтом, а D - наименее значимым. Это закончилось бы как:

A = 01000000
B = 00000101
C = 00101011
D = 11100011
val = 01000000 00000101 00101011 11100011

Цвета часто сохраняются таким образом (самый старший байт либо игнорируется, либо используется как альфа):

A = 255 = 11111111
R = 21 = 00010101
G = 255 = 11111111
B = 0 = 00000000
Color = 11111111 00010101 11111111 00000000

Чтобы снова найти значения, просто сдвиньте биты вправо, пока они не окажутся внизу, а затем замаскируйте оставшиеся биты высшего порядка:

Int Alpha = Color >> 24
Int Red = Color >> 16 & 0xFF
Int Green = Color >> 8 & 0xFF
Int Blue = Color & 0xFF

0xFF - это то же самое, что и 11111111. По сути, для Red вы должны сделать это:

Color >> 16 = (filled in 00000000 00000000)11111111 00010101  (removed 11111111 00000000)
00000000 00000000 11111111 00010101 &
00000000 00000000 00000000 11111111 =
00000000 00000000 00000000 00010101 (The original value)

Стоит отметить, что таблицы истинности одного бита, перечисленные в качестве других ответов, работают только с одним или двумя входными битами одновременно. Что происходит, когда вы используете целые числа, такие как:

int x = 5 & 6;

Ответ заключается в двоичном расширении каждого входа:

  5 = 0 0 0 0 0 1 0 1
& 6 = 0 0 0 0 0 1 1 0
---------------------
      0 0 0 0 0 1 0 0

Каждая пара битов в каждом столбце проходит через функцию "И", чтобы получить соответствующий выходной бит в нижней строке. Таким образом, ответ на вышеприведенное выражение - 4. Процессор выполнил (в этом примере) 8 отдельных операций "И" параллельно, по одной для каждого столбца.

Я упоминаю об этом, потому что я до сих пор помню, как это "АГА!" момент, когда я узнал об этом много лет назад.

Побитовые операторы - это операторы, работающие по очереди.

И равен 1, только если оба его входа равны 1.

ИЛИ равен 1, если один или несколько его входов равны 1.

XOR равен 1, только если точно один из его входов равен 1.

НЕ равен 1, только если его вход равен 0.

Их лучше всего описать как таблицы истинности. Возможности входов находятся сверху и слева, результирующий бит является одним из четырех (два в случае НЕ, поскольку он имеет только один вход) значений, показанных на пересечении двух входов.

AND|0 1      OR|0 1
---+----    ---+----
  0|0 0       0|0 1
  1|0 1       1|1 1

XOR|0 1     NOT|0 1
---+----    ---+---
  0|0 1        |1 0
  1|1 0

Один пример: если вы хотите только младшие 4 бита целого числа, вы И это с 15 (двоичный код 1111) так:

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011

Это побитовые операторы, все они поддерживаются в JavaScript:

  • op1 & op2 - AND оператор сравнивает два бита и генерирует результат 1, если оба бита равны 1; в противном случае возвращается 0.

  • op1 | op2 - OR оператор сравнивает два бита и генерирует результат 1, если биты дополняют друг друга; в противном случае возвращается 0.

  • op1 ^ op2 - EXCLUSIVE-OR Оператор сравнивает два бита и возвращает 1, если один из битов равен 1, и дает 0, если оба бита равны 0 или 1.

  • ~op1 - COMPLEMENT Оператор используется для инвертирования всех битов операнда.

  • op1 << op2 - SHIFT LEFT Оператор перемещает биты влево, отбрасывает крайний левый бит и назначает крайнему правому биту значение 0. Каждое перемещение влево эффективно умножает op1 на 2.

  • op1 >> op2 - SHIFT RIGHT Оператор перемещает биты вправо, отбрасывает крайний правый бит и назначает крайнему левому биту значение 0. Каждое перемещение вправо эффективно делит op1 пополам. Крайний левый бит знака сохраняется.

  • op1 >>> op2 - SHIFT RIGHT - ZERO FILL Оператор перемещает биты вправо, отбрасывает крайний правый бит и назначает крайнему левому биту значение 0. Каждое перемещение вправо эффективно делит op1 пополам. Самый левый бит знака сбрасывается.

В цифровом компьютерном программировании побитовая операция работает с одной или несколькими битовыми комбинациями или двоичными числами на уровне их отдельных битов. Это быстрое примитивное действие, непосредственно поддерживаемое процессором, и используется для манипулирования значениями для сравнения и расчетов.

операции:

  • побитовое И

  • побитовое ИЛИ

  • поразрядно НЕ

  • побитовый XOR

  • так далее

Элемент списка

    AND|0 1        OR|0 1 
    ---+----      ---+---- 
      0|0 0         0|0 1 
      1|0 1         1|1 1 

   XOR|0 1        NOT|0 1 
   ---+----       ---+--- 
     0|0 1           |1 0 
     1|1 0

Например.

    203: 1100 1011
AND  15: 0000 1111
------------------
  =  11: 0000 1011

Использование побитового оператора

  • Операторы левого и правого сдвига эквивалентны умножению и делению на x * 2y соответственно.

Например.

int main()
{
     int x = 19;
     printf ("x << 1 = %d\n" , x <<1);
     printf ("x >> 1 = %d\n", x >>1);
     return 0;
}
// Output: 38 9
  • Оператор & может быть использован для быстрой проверки, является ли число нечетным или четным

Например.

int main()
{
    int x = 19;
    (x & 1)? printf("Odd"): printf("Even");
    return 0;
 }
// Output: Odd
  • Быстрый поиск минимум х и у без if else Постулаты

Например.

int min(int x, int y)
{
    return y ^ ((x ^ y) & - (x < y))
}
  • Десятичное в двоичное преобразование

Например.

#include <stdio.h>
int main ()
{
    int n , c , k ;
    printf("Enter an integer in decimal number system\n " ) ;
    scanf( "%d" , & n );
    printf("%d in binary number
    system is: \n " , n ) ;
    for ( c = 31; c >= 0 ; c -- )
    {
         k = n >> c ;
         if ( k & 1 )
              printf("1" ) ;
         else
              printf("0" ) ;
      }
      printf(" \n " );
      return 0 ;
}
  • Шифрование с помощью шлюза XOR является популярной техникой, потому что оно универсально и широко используется программистом.
    • побитовый оператор XOR является наиболее полезным оператором с точки зрения технического интервью.

побитовое смещение работает только с + ве число

Также существует широкий спектр использования побитовой логики

Чтобы разбить его еще немного, он имеет непосредственное отношение к двоичному представлению рассматриваемого значения.

Например (в десятичном виде):
х = 8
у = 1

вышел бы (в двоичном виде):
х = 1000
у = 0001

Оттуда вы можете выполнять вычислительные операции, такие как "и" или "или"; в этом случае:
х | у = 
1000 
0001 |
------
1001

или...9 в десятичном виде

Надеюсь это поможет.

Когда упоминается термин "побитовый", иногда уточняется, что это не "логический" оператор.

Например, в JavaScript побитовые операторы обрабатывают свои операнды как последовательность из 32 битов (нули и единицы); Между тем, логические операторы обычно используются с логическими (логическими) значениями, но могут работать с небулевыми типами.

Возьмем, например, expr1 && expr2.

Возвращает expr1, если его можно преобразовать в false; в противном случае возвращает expr2. Таким образом, при использовании с логическими значениями && возвращает true, если оба операнда имеют значение true; в противном случае возвращает false.

a = "Cat" && "Dog"     // t && t returns Dog
a = 2 && 4     // t && t returns 4

Как уже отмечали другие, 2 & 4 - это побитовое И, поэтому оно вернет 0.

Вы можете скопировать следующее в test.html или что-то еще и протестировать:

<html>
<body>
<script>
    alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
        + "2 && 4 = " + (2 && 4) + "\n"
        + "2 & 4 = " + (2 & 4));
</script>

Это могло бы помочь думать об этом таким образом. Вот как работает AND (&):

Это в основном говорит, что оба эти числа одно, поэтому, если у вас есть два числа 5 и 3, они будут преобразованы в двоичную, и компьютер будет думать

         5: 00000101
         3: 00000011

оба равны: 00000001 0 ложно, 1 верно

Таким образом, И 5 и 3 - это одно. Оператор OR (|) делает то же самое, за исключением того, что для вывода 1 должно быть только одно из чисел, а не оба.

Хотя другие ответы хороши, но я все еще не мог понять практические варианты использования побитовых операторов.

Наконец, видео Мошфега Хамедани о побитовых операторах JavaScript действительно позволило мне понять эти термины.

Я продолжал слышать о том, насколько медленными были битовые операторы JavaScript. Я сделал несколько тестов для своего последнего поста в блоге и обнаружил, что они были на 40-80% быстрее, чем арифметическая альтернатива в нескольких тестах. Возможно, они были медленными. В современных браузерах я их люблю.

У меня есть один случай в моем коде, который будет быстрее и легче читать из-за этого. Я буду держать глаза открытыми для большего.

Другие вопросы по тегам