Что означает побитовое XOR (исключающее ИЛИ)?

Я пытаюсь понять бинарные операторы в С# или вообще, в частности ^ - эксклюзивное или.

Например:

Дан массив положительных целых чисел. Все числа встречаются четное количество раз, кроме одного числа, которое встречается нечетное количество раз. Найдите число за время O(n) и постоянное пространство.

Это можно сделать с помощью ^ следующим образом: выполнить побитовое XOR всех элементов. Наконец, мы получаем число, которое имеет нечетные вхождения.

Как это работает?

Когда я делаю:

int res = 2 ^ 3;  
res = 1;  
int res = 2 ^ 5;  
res = 7;  
int res = 2 ^ 10;  
res = 8;  

Что на самом деле происходит? Какая еще битовая магия? Любую ссылку, которую я могу найти и узнать о них больше?


person DarthVader    schedule 18.06.2011    source источник
comment
Это бинарное сложение без переносов. 0+0 = 0, 1+0=1, 0+1=1 и 1+1=0 (без переноса). Обычным двоичным сложением для 1+1 будет перенос 0 на 1.   -  person dbasnett    schedule 20.06.2011


Ответы (8)


Чтобы увидеть, как это работает, сначала вам нужно записать оба операнда в двоичном формате, потому что побитовые операции работают с отдельными битами.

Затем вы можете применить таблицу истинности для вашего конкретного оператора. Он действует на каждую пару битов, имеющих одинаковую позицию в двух операндах (одинаковое разрядное значение). Таким образом, самый левый бит (MSB) A объединяется с MSB B для получения MSB результата.

Пример: 2^10:

    0010 2
XOR 1010 8 + 2
    ----
    1    xor(0, 1)
     0   xor(0, 0)
      0  xor(1, 1)
       0 xor(0, 0)
    ----
 =  1000 8

И результат 8.

person Ben Voigt    schedule 18.06.2011

Я знаю, что это довольно старый пост, но я хотел упростить ответ, так как я наткнулся на него, когда искал что-то другое.
XOR (исключающее ИЛИ/либо, либо), можно перевести просто как включение/выключение.
Что либо исключит (если существует), либо включит (если не существует) указанные биты.

Используя 4 бита (1111), мы получаем 16 возможных результатов от 0 до 15:

 decimal | binary | bits (expanded)
       0 | 0000   | 0
       1 | 0001   | 1
       2 | 0010   | 2
       3 | 0011   | (1+2)
       4 | 0100   | 4
       5 | 0101   | (1+4)
       6 | 0110   | (2+4) 
       7 | 0111   | (1+2+4)
       8 | 1000   | 8
       9 | 1001   | (1+8)
      10 | 1010   | (2+8)
      11 | 1011   | (1+2+8)
      12 | 1100   | (4+8)
      13 | 1101   | (1+4+8)
      14 | 1110   | (2+4+8)
      15 | 1111   | (1+2+4+8)

десятичное значение слева от двоичного значения — это числовое значение, используемое в XOR и других побитовых операциях. операций, представляющих общее значение связанных битов. См. Формат номера компьютера и Двоичное число — десятичное число для получения дополнительной информации.

Например: 0011 биты 1 и 2 включены, а биты 4 и 8 выключены. Который представлен как десятичное значение 3 для обозначения включенных битов и отображается в расширенной форме как 1+2.


Что касается логики XOR, вот несколько примеров
Из исходного поста

2^3 = 1

  • 2 входит в группу 1+2 (3) remove 2 = 1

2^5 = 7

  • 2 не входит в группу 1+4 (5) add 2 = 1+2+4 (7)

2^10 = 8

  • 2 входит в группу 2+8 (10) remove 2 = 8

Дополнительные примеры

1^3 = 2

  • 1 входит в группу 1+2 (3) remove 1 = 2

4^5 = 1

  • 4 входит в группу 1+4 (5) remove 4 = 1

4^4 = 0

  • 4 является членом самого себя remove 4 = 0

1^2^3 = 0
Логика: ((1^2)^(1+2))

  • (1^2) 1 не является членом 2 add 2 = 1+2 (3)
  • (3^3) 1 и 2 являются членами 1+2 (3) удалить 1+2 (3) = 0

1^1^0^1 = 1
Логика: (((1^1)^0)^1)

  • (1^1) 1 является членом 1 удалить 1 = 0
  • (0^0) 0 является членом 0 удалить 0 = 0
  • (0^1) 0 не является членом 1 добавить 1 = 1

1^8^4 = 13
Логика: ((1^8)^4)

  • (1^8) 1 не входит в число 8 добавить 1 = 1+8 (9)
  • (9^4) 1 и 8 не являются элементами 4 add 1+8 = 1+4+8 (13)

4^13^10 = 3
Логика: ((4^(1+4+8))^(2+8))

  • (4^13) 4 входит в группу 1+4+8 (13) remove 4 = 1+8 (9 )
  • (9^10) 8 входит в группу 2+8 (10) удалить 8 = 2
  • 1 не является членом группы 2+8 (10) add 1 = 1+2 ( 3)

4^10^13 = 3
Логика: ((4^(2+8))^(1+4+8))

  • (4^10) 4 не входит в группу 2+8 (10) add 4 = 2+4+8 ( 14)
  • (14^13) 4 и 8 являются элементами 1+4+8 (13) удалить 4+8 = 1< /сильный>
  • 2 не является членом группы 1+4+8 (13) add 2 = 1+2 (3)
person Will B.    schedule 29.04.2013
comment
Вы по-прежнему получаете +1. Спасибо за усилия для новых пользователей и для тех, кто любопытен. - person DarthVader; 29.04.2013
comment
Потрясающий. Откуда вы узнали об этом? Можете ли вы дать ссылку для изучения других побитовых операций? - person ashwani; 04.01.2016
comment
@user132458 user132458, честно говоря, это то, что я понял о том, как работают побитовые операции. Лучшие ресурсы будут зависеть от вашего варианта использования, например, от языка программы. Например: C# против PHP против Python и как они используют побитовые операции и их ограничения. Однако вики является достойным ресурсом в отношении общих побитовых операций en.wikipedia.org/wiki/Bitwise_operation. - person Will B.; 04.01.2016
comment
В 2^5 вы сказали, что 2 не является членом 1+4 (5) добавить 2 = 1+2+4 (7). Но почему вы считаете, что 5 равно 1+4, а не 2+3? В этом случае 2 будет членом 2+3. Я не получил эту часть. - person Alisson; 17.04.2018
comment
Никакое объяснение не могло быть лучше этого. - person Raghav salotra; 10.06.2018

Другой способ показать это — использовать алгебру XOR; вам не нужно ничего знать об отдельных битах.

Для любых чисел x, y, z:

XOR является коммутативным: x ^ y == y ^ x

XOR является ассоциативным: x ^ (y ^ z) == (x ^ y) ^ z

Идентификатор 0: x ^ 0 == x

Каждый элемент является своим обратным: x ^ x == 0

Учитывая это, несложно доказать сформулированный результат. Рассмотрим последовательность:

a ^ b ^ c ^ d ...

Поскольку XOR является коммутативным и ассоциативным, порядок не имеет значения. Итак, рассортируйте элементы.

Теперь любые соседние одинаковые элементы x ^ x можно заменить на 0 (свойство самоинверсии). И любой 0 можно убрать (потому что это тождество).

Повторяйте как можно дольше. Любое число, встречающееся четное число раз, имеет целое число пар, поэтому все они становятся равными 0 и исчезают.

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

[Обновить]

Обратите внимание, что это доказательство требует только определенных предположений об операции. В частности, предположим, что множество S с оператором . имеет следующие свойства:

Ассоциативность: x . (y . z) = (x . y) . z для любых x, y и z в S.

Идентичность: существует единственный элемент e, такой что e . x = x . e = x для всех x в S.

Закрытие: для любых x и y в S x . y также находится в S.

Самоинверсия: для любого x в S x . x = e

Как оказалось, нам не нужно предполагать коммутативность; мы можем это доказать:

(x . y) . (x . y) = e  (by self-inverse)
x . (y . x) . y = e (by associativity)
x . x . (y . x) . y . y = x . e . y  (multiply both sides by x on the left and y on the right)
y . x = x . y  (because x . x = y . y = e and the e's go away)

Теперь я сказал, что «вам не нужно ничего знать об отдельных битах». Я думал, что любой группы, удовлетворяющей этим свойствам, будет достаточно, и что такая группа не обязательно должна быть изоморфна целым числам по XOR.

Но @Steve Jessup доказал, что я ошибаюсь в комментариях. Если вы определяете скалярное умножение на {0,1} как:

0 * x = 0
1 * x = x

...тогда эта структура удовлетворяет всем аксиомам векторного пространства по модулю целых чисел 2.

Таким образом, любая такая структура изоморфна набору векторов битов при покомпонентном XOR.

person Nemo    schedule 18.06.2011
comment
И у него есть эта алгебра, потому что это просто сложение в векторном пространстве над простым полем порядка 2. И это потому, что в этом поле сумма двух значений равна 1 тогда и только тогда, когда ровно одно из слагаемых равно 1. Логическое исключающее ИЛИ из двух логических значений истинно тогда и только тогда, когда истинно ровно одно из операндов. Таким образом, логическое XOR добавляет в поле, а затем побитовое делает его векторным пространством. - person Steve Jessop; 19.06.2011
comment
@Steve: справедливое замечание. Что приводит к интересному вопросу... Любая группа, подчиняющаяся этим отношениям, будет иметь свойство, указанное в вопросе. Но все ли такие группы изоморфны (Z/2Z)^n для некоторого n? - person Nemo; 19.06.2011
comment
@Nemo: это может зависеть от того, что вы подразумеваете под n. Например, рассмотрим векторные пространства с бесконечными базами над этим полем. - person Steve Jessop; 19.06.2011
comment
@Steve: Хорошо, тогда назови это конечной группой. Другими словами, если конечная группа ассоциативна, коммутативна и самообратна, она обязательно изоморфна некоторому n-мерному векторному пространству над {0,1}? - person Nemo; 19.06.2011
comment
Я так думаю, да — если мы возьмем любую группу с такими свойствами и определим очевидное скалярное умножение, то у нас будет векторное пространство над этим полем. Независимо от того, обязательно ли оно имеет размерность, это эквивалентно аксиоме выбора (доказательство проще в одном направлении, чем в другом), но если оно конечно, то оно определенно имеет место :-) - person Steve Jessop; 19.06.2011
comment
@Steve: Извини, но я не слежу за тобой. Что такое очевидное скалярное умножение в этом контексте? Все, что у нас есть, это групповые свойства плюс упомянутые; нет прямого отображения на вещественные числа, целые числа или 0/1. Иными словами, если элементы группы a и b удовлетворяют этим свойствам, каково их скалярное произведение? - person Nemo; 19.06.2011
comment
Используя обозначение, что 0 — это скаляр 0, а e — идентификатор группы, очевидное скалярное умножение — это 0 * a == e и 1 * a == a для всех элементов a в группе. На самом деле это единственное скалярное умножение, которое вы можете определить и которое делает его векторным пространством — эти тождества выполняются для всех векторных пространств независимо от поля. Я не говорю о скалярном произведении двух векторов, которое не является частью определения векторного пространства и не нуждается в определении. Векторное пространство с определенным скалярным произведением двух векторов называется пространством внутреннего произведения. - person Steve Jessop; 19.06.2011
comment
Я хочу сказать, что как только вы определили умножение на 0 или 1, группа немедленно является векторным пространством над (Z/2Z), что доказывает изоморфизм. - person Steve Jessop; 19.06.2011
comment
@Steve: За исключением того, что моему доказательству не нужно, чтобы 0 был скалярным нулем. Позвольте мне перефразировать мой вопрос. Предположим, у нас есть конечная группа, которая является ассоциативной, коммутативной и самообратной. Предположим, что у него есть идентификатор (не обязательно связанный с целым числом 0). Это все, что вы знаете о группе; его элементы могут быть любыми, они просто подчиняются этим отношениям. Обязательно ли эта группа изоморфна некоторому n-мерному векторному пространству над {0,1}? (Обратите внимание, что мое доказательство показывает, что любая такая группа обладает свойством, описанным в вопросе; на самом деле оно не полагалось на то, что число 0 является идентификатором.) - person Nemo; 19.06.2011
comment
@Немо: да, это так. Векторное пространство по определению состоит из коммутативной группы, поля и скалярной операции умножения, которая представляет собой бинарный оператор, который берет член поля (скаляр) вместе с членом группы (вектор) и возвращает член группа. Скалярный ноль по определению является мультипликативной идентичностью поля. Поскольку полем, которое я использую для построения моего векторного пространства, является Z(2), это означает, что скалярный нуль является целым числом 0. Это не имеет ничего общего с тем фактом, что в побитовом XOR groupidentity также оказывается целым числом 0. - person Steve Jessop; 19.06.2011
comment
@Steve: Мы все еще разговариваем друг с другом. Дай мне попробовать снова. Что если скалярного умножения вообще нет? Что, если все, что вы знаете, это то, что групповое умножение (которое берет два элемента группы и дает еще один элемент группы) подчиняется заданным свойствам? Имея только эти свойства, в том числе тот факт, что некоторый элемент, не обязательно называемый 0, является тождеством, можете ли вы доказать изоморфизм целых чисел по XOR? - person Nemo; 19.06.2011
comment
Я определяю скалярное умножение. Я просто изобретаю этот бинарный оператор, утверждая, что 0*a==e и 1*a==a. Я как математик имею право определять функции, и причина, по которой эта функция интересна, заключается в том, что вместе с полем Z(2) и самообратной группой, которые вы предоставляете, она удовлетворяет аксиомам векторного пространства (я утверждаю это, не имея показал работу, чтобы доказать это). Кстати, если вы настаиваете на вызове группового бинарного оператора умножения, это может сильно запутать — пожалуйста, обращайтесь к нему как к сложению. Логически разницы нет. - person Steve Jessop; 19.06.2011
comment
И я не называю идентификатор группы 0. Я называю это e. Я называю мультипликативную идентичность поля Z(2) 0. [OOPS - нет, я называю добавочный идентификатор поля Z(2) 0. Я сделал ту же ошибку, когда сказал: «Скалярный ноль по определению является мультипликативной идентичностью поля». Я имел в виду, что скалярный ноль по определению является аддитивной идентичностью поля. Здесь уже поздновато]. - person Steve Jessop; 19.06.2011
comment
@Steve: Хорошо, я согласен, что вы определили, как умножать элемент группы на скаляр 0 или 1. Теперь, как вы определяете скалярное произведение двух элементов группы, чтобы получить скаляр 0 или 1? (Учитывая, что элементы группы не имеют компонентов... Пока.) То есть, скажем, я даю вам два различных элемента группы a и b. Определите их точечный продукт, используя только заданные свойства плюс определение элемента скалярного умножения. (Думаю, вам это нужно для завершения построения; поправьте меня, если я ошибаюсь.) - person Nemo; 19.06.2011
comment
Я не определяю их скалярный продукт. Мне не нужно, чтобы доказать изоморфизм, потому что скалярное произведение не является частью аксиоматизации векторного пространства. Тем не менее, после доказательства того, что то, с чем мы имеем дело, является (изоморфным) конечным векторным пространством над Z (2), очевидным скалярным произведением для определения будет взятие основы векторного пространства (мне все равно, какой один), выразить a и b в терминах этого базиса, и тогда скалярное произведение определяется как количество базисных элементов, которые имеют коэффициент 1 в обоих разложениях (т. е. сумма произведений соответствующих коэффициентов) по модулю 2. - person Steve Jessop; 19.06.2011
comment
@Steve: Хорошо, наконец-то я следую за тобой. Интересный. Единственное место, где ваша конструкция использует самоинверсное предположение, - это выполнение аксиомы распределения скалярного умножения поверх аксиомы сложения векторов, я думаю, что (1 + 1)v = v + v = 0v = e. Очень красиво ... Я обновлю свой ответ. - person Nemo; 19.06.2011
comment
@Немо: круто. Хотя в конце я немного увлекся. Скалярное произведение, которое я определил, следует обычному образцу скалярного произведения, но на самом деле эта функция не образует скалярный продукт над конечным полем. Обычно внутренние продукты определяются только для полей, превышающих действительные числа (или больше). - person Steve Jessop; 19.06.2011

Это основано на том простом факте, что XOR числа с самим собой дает ноль.

и XOR числа с 0 приводит к самому числу.

Итак, если у нас есть массив = {5,8,12,5,12}.

5 встречается 2 раза. 8 встречается 1 раз. 12 встречается 2 раза.

Нам нужно найти число, встречающееся нечетное количество раз. Ясно, что 8 - это число.

Начнем с res=0 и XOR со всеми элементами массива.

int res=0; for(int i:array) res = res ^ i;

    1st Iteration: res = 0^5 = 5
    2nd Iteration: res = 5^8 
    3rd Iteration: res = 5^8^12
    4th Iteration: res = 5^8^12^5 = 0^8^12 = 8^12
    5th Iteration: res = 8^12^12 = 8^0 = 8
person skmangalam    schedule 04.05.2018
comment
Спасибо за отличное объяснение! - person KMC; 25.01.2019
comment
Спасибо за отличное объяснение! - person Aman Raheja; 18.09.2020
comment
Это то, что я искал. Спасибо! - person Nikhil Goyal; 17.07.2021

Побитовые операторы обрабатывают биты внутри целочисленного значения как крошечный массив битов. Каждый из этих битов подобен маленькому значению bool. Когда вы используете оператор побитового исключения или, одна из интерпретаций того, что делает оператор, такова:

  • для каждого бита в первом значении переключать бит, если установлен соответствующий бит во втором значении

Чистый эффект заключается в том, что один бит начинается с false, и если общее количество «переключателей» четное, оно все равно будет false в конце. Если общее количество «переключателей» нечетное, в конце будет true.

Просто подумайте о «крошечном массиве логических значений», и это начнет обретать смысл.

person Rick Sladkey    schedule 18.06.2011

Определение оператора XOR (исключающее ИЛИ) над битами таково:

0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0

Один из способов представить это — сказать, что «1» с правой стороны изменяет бит с левой стороны, а 0 с правой стороны не меняет бит с левой стороны. Однако XOR является коммутативным, поэтому то же самое верно, если стороны перевернуты. Поскольку любое число может быть представлено в двоичной форме, любые два числа могут быть объединены XOR вместе.

Чтобы доказать его коммутативность, вы можете просто взглянуть на его определение и увидеть, что для каждой комбинации битов с обеих сторон результат будет одинаковым, если стороны будут изменены. Чтобы доказать его ассоциативность, вы можете просто запустить все возможные комбинации 3 битов, объединенных XOR друг с другом, и результат останется тем же, независимо от порядка.

Теперь, когда мы доказали вышеизложенное, давайте посмотрим, что произойдет, если мы выполним операцию XOR над тем же числом. Поскольку операция работает с отдельными битами, мы можем протестировать ее только на двух числах: 0 и 1.

0 XOR 0 = 0
1 XOR 1 = 0

Итак, если вы выполняете операцию XOR над числом, вы всегда получаете 0 (верите или нет, но это свойство XOR использовалось компиляторами, когда 0 нужно загрузить в регистр ЦП. Быстрее выполнить битовую операцию чем явно вставлять в регистр 0. Компилятор просто создаст ассемблерный код для XOR регистра на себя).

Теперь, если X XOR X равно 0, а XOR является ассоциативным, и вам нужно выяснить, какое число не повторяется в последовательности чисел, где все остальные числа повторялись два (или любое другое нечетное количество раз). Если у нас есть повторяющиеся числа вместе, они будут XOR до 0. Все, что XOR-ed с 0, останется самим собой. Таким образом, из-за XOR такой последовательности вы в конечном итоге получите число, которое не повторяется (или повторяется четное количество раз).

person Pawel Veselov    schedule 18.06.2011

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

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

  • входные данные в двоичной форме
  • таблица истинности, которая говорит вам, как «смешивать» входные данные, чтобы сформировать результат

Для XOR таблица истинности проста:

1^1 = 0
1^0 = 1
0^1 = 1
0^0 = 0

Чтобы получить бит n в результате, вы применяете правило к битам n в первом и втором входах.

Если вы попытаетесь вычислить 1^1^0^1 или любую другую комбинацию, вы обнаружите, что результат равен 1, если число единиц нечетное, и 0 в противном случае. Вы также обнаружите, что любое число, объединенное XOR с самим собой, равно 0, и это не имеет значения, в каком порядке вы выполняете вычисления, например. 1^1^(0^1) = 1^(1^0)^1.

Это означает, что когда вы выполняете XOR для всех чисел в вашем списке, те, которые являются дубликатами (или представляют четное количество раз), будут XOR до 0, и у вас останется только тот, который присутствует нечетное количество раз.

person Andrei    schedule 18.06.2011

Как видно из названия (побитовый), он работает между битами. Давайте посмотрим, как это работает, например, у нас есть два числа a = 3 и b = 4, двоичное представление 3 — 011, а 4 — 100, поэтому в основном xor для тех же битов равен 0, а для противоположных битов это 1. В данном примере 3^4, где ^ — символ xor, даст нам 111, десятичное значение которого будет равно 7. Для другого примера, если вы дали массив, в котором каждый элемент встречается дважды, кроме одного элемента, и вы нужно найти этот элемент. Как вы можете это сделать? простой xor одних и тех же чисел всегда будет 0, а число, которое встречается ровно один раз, будет вашим выходом. потому что вывод любого одного числа с 0 будет иметь тот же номер имени, потому что число будет иметь установленные биты, которых нет у нуля.

person Gaurav Bharti    schedule 01.08.2020