Итак, у меня есть числовые значения от 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'
Использование двоичной операции И для выбора только соответствующих битов:
$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'
Других решений пока нет …