Побитовый XOR — Как выполнить двоичные операции на клев / тетрада в PHP?

Итак, у меня есть числовые значения от 0 до 15, поэтому я сохранил их в шестнадцатеричных кодах (от 0 до f). Теперь у меня есть строка данных, содержащая значения шестнадцатеричного кода моих полубайтов.

Данные выглядят так:

a0fc3d78270db962e4ba525cf3acd

Каков точный / элегантный / быстрый способ выполнения двоичного xor на двух клевах и какой самый быстрый способ выполнения двоичного кода на клеве?

Сейчас я имею в виду сначала преобразовать полубайты в полные байты:

$nibble = "c";
$numeric = ord($nibble);
$byte = ($numeric<58)?chr($numeric-48):chr($numeric-55);

Затем выполните желаемую операцию (xor или нет) с этими байтами и снова преобразовайте полученное значение в полубайт.

$byte1 = chr(7); $byte2=chr(12);
$xor_val = $byte1 ^ $byte2;
$numeric = ord($xor_val);
$nibble = ($numeric<58)?chr($numeric+48):chr($numeric+55);

Проблема с этим подходом состоит в том, что, если я применяю операцию not (~) к байту, он также инвертирует первые 4 бита (следовательно, добавляя 1111 к левой стороне куска), и мне приходится сталкиваться с дополнительной сложностью: вычитая 240 из значения ord () результата, прежде чем я преобразую его в кусок с кодом, представленным выше. Это не только усложняет будущие обновления кода, но и усложняет интерпретацию функциональности кода в будущем.

Каков наилучший / точный способ выполнения побитового xor, а не на полубайтах, с получением результирующего значения в виде шестнадцатеричного кода (строки)?

Примеры:

'3' xnor 'a' = '6'
'c' xnor '5' = '6'
'b' xnor '8' = 'c'

1

Решение

Использование двоичной операции И для выбора только соответствующих битов:

$nibble1 = hexdec('3');
$nibble2 = hexdec('a');

// nibble1 xnor nibble2
$r = ~($nibble1 ^ $nibble2) & 0x0F;

echo dechex($r); // '6'

Это называется «маскированием» битов, где 0x0F называется «маской».

Без маскировки, результат операции ~(0x0b ^ 0x08) было бы ffffffffffffffffc, из-за того, что PHP представляет целые числа в виде 64-битных длин.

Теперь, когда мы применяем маску, происходит следующее (я упустил 4 старших байта для упрощения визуализации):

11111111 11111111 11111111 11111100 (ffffffffc)
00000000 00000000 00000000 00001111 (00000000f)
----------------------------------- & (binary AND)
00000000 00000000 00000000 00001100 (00000000c)

Мы «выбираем» только нижний последний клев.

Чтобы замаскировать верхний клев, используйте 0xF0 и (необязательно) сдвиг вправо 4.

$byte1 = hexdec('3f');
$byte2 = hexdec('a5');

$r = (~($byte1 ^ $byte2) & 0xF0) >> 4;

echo dechex($r); // Also '6'
1

Другие решения

Других решений пока нет …