Замена "==" побитовыми операторами - PullRequest
24 голосов
/ 12 ноября 2010

Используя только побитовые операторы (|, &, ~, ^, >>, <<) и другие базовые операторы, такие как +, - и!, Можно ли заменить "==" ниже? </p>

int equal(int x, int y) {
    return x == y;
}

Ответы [ 6 ]

63 голосов
/ 12 ноября 2010

Помните, что XOR точно так же, как NOT EQUALS, а XNOR точно так же, как EQUALS.Итак, следующее даст вам именно то, что вы хотите:

return !(x ^ y);
21 голосов
/ 12 ноября 2010

Два числа равны, если между ними нет разницы:

int equal(int x, int y){
   return !(x-y);
}
14 голосов
/ 12 ноября 2010

Оператор C ! на самом деле является просто сокращением для != 0, поэтому его использование кажется очень близким к мошенничеству:)

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

int t = (x - y) | (y - x); // <0 iff x != y, 0 otherwise
t >>= 31; // -1 iff x != y, 0 otherwise
return 1 + t; // 0 iff x != y, 1 otherwise

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

  1. Коды условий, возвращаемые для арифметических операций (например, x86 и ARM делают это). В этом случае обычно есть команда сравнения, которая вычитает два значения, не записывает обратно в регистр целых чисел, но устанавливает код / ​​флаги условия на основе результата.
  2. Больше RISC-подобных платформ обычно имеют прямые операнды «ветвь, если равен» и «ветвь, если меньше, чем», которые выполняют сравнение и ветвление на основе результата. Это в основном эквивалентно коду C

    if (a == b) goto label;
    

    или

    if (a < b) goto label;
    

    все в одной машинной инструкции.

2 голосов
/ 12 ноября 2010

Этот пример аналогичен вычитанию, но он более точен в отношении того, как некоторые архитектуры выполняют сравнение регистров (как я полагаю, ARM).

return !(1 + ~x + y);

1 означает входной бит переноса вАЛУ.Одно число x побитно дополняется.Взяв дополнение и добавив 1, получим дополнение числа к двум (x становится -x), а затем добавляется к другому числу, чтобы получить разницу для определения равенства.

Так что, если оба числаравный, вы получите -x + x => 0.

(На уровне регистра оператор ! не выполнен, и вы просто проверяете «нулевой бит» регистра кодов состояния или флагов, который устанавливается, если операция регистра дает нулевой результати ясно в противном случае.)

1 голос
/ 04 августа 2015

Поскольку XOR совпадает с (! =), Следовательно, (x ^ y) вернет 0 только для равных значений.Мое мнение следующее: он разумный, использует побитовый оператор и работает.

int notEqual(int x, int y){
        return (x ^ y);
}
0 голосов
/ 12 ноября 2010

Мой взгляд на это

int equal(int x, int y){
   if((x & ~y) == 0)
       return 1;
   else
       return 0; 
}

Объяснение: Если x == y, то x & ~y оценивается как 0, возвращает 1, иначе возвращает 0 как x!=y.

Edit1: The above is equivalent to 

int equal(int x, int y){
    return !(x & ~y) ; // returns 1 if equal , 0 otherwise. 
}

Приведенный выше код завершается ошибкой в ​​некоторых случаях, когда старший бит становится равным 1. Решение состоит в том, чтобы добавить 1. То есть правильный ответ -

return !(x & (~y +1) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...