Как эффективно конвертировать положительное число в базе -2 в отрицательное в базе — 2?

Старое название вопроса: Как эффективно разбить двоичную строку на группы по 10, 0, 11?

У меня есть несколько строк в качестве входных данных, которые представляют собой двоичное представление числа.
Например:

10011
100111
0111111
11111011101

Мне нужно разбить эти строки (или массивы) на группы по 10, 0 и 11, чтобы заменить их.

10 => 11
0 => 0
11 => 10

Как это сделать? Я пробовал эти варианты, но не работает.

preg_match('/([10]{2})(0{1})([11]{2})/', $S, $matches);

Должно быть [10] [0], [11] для ввода 10011.
И это должно быть 11010 при замене.

UPD1.

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

Для этого случая 0111111 возможно добавить 0 в конце. Тогда правила будут применяться. И мы могли бы удалить ведущие нули в результате. Выход будет 101010.

UPD2.

@Wiktor Stribiżew предложил идею, как сделать замену немедленно, не разбивая байты на группы.
Но у меня уже есть более быстрое решение.

$S = strtr($S, $rules);

Смысл этого вопроса состоит не в замене, а в получении массива желаемых групп [11] [0] [10].

UPD3.

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

function solution2($A)
{
$S = implode('', $A);

//we could add leading 0
if (substr($S, strlen($S) - 1, 1) == 1) {
$S .= '0';
}

$rules = [
'10' => '11',
'0'  => '0',
'11' => '10',
];

$S = strtr($S, $rules);

$arr = str_split($S);

//remove leading 0
while ($arr[count($arr) - 1] == 0) {
array_pop($arr);
}

return $arr;
}

Но решение в ответе @Alex Blex быстрее.

1

Решение

Отвечая на вопрос

алгоритм для преобразования положительного числа в базе -2 в отрицательное в базе -2

Я считаю, что следующая функция более эффективна, чем регулярное выражение:

function negate($negabin)
{
$mask = 0xAAAAAAAAAAAAAAA;
return decbin((($mask<<1)-($mask^bindec($negabin)))^$mask);
}

Параметр является положительным значением int60 в нотации с основанием -2, например, 11111011101.

Функция преобразует параметр в базу 10, отрицает его и преобразует обратно в базу -2, как описано в вики: https://en.wikipedia.org/wiki/Negative_base#To_negabinary

Работает на 64-битной системе, но может быть легко адаптирован для работы на 32-битной.

1

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

Вы можете использовать простой /11|10/ регулярное выражение с preg_replace_callback:

$s = '10011';
echo preg_replace_callback("/11|10/", function($m) {
return $m[0] == "11" ? "10" : "11"; // if 11 is matched, replace with 10 or vice versa
}, $s);
// => 11010

Увидеть онлайн PHP демо.

3

По вопросам рекламы [email protected]