如何有效地将基数-2中的正数转换为基数-2中的负数? -

时间:2017-03-22 12:07:35

标签: php regex binary negation

  

旧问题名称:如何在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);

10011输入应为[10] [0],[11]。 更换时应该是11010。

UPD1。

实际上,我正在尝试做一个否定算法,用于将基数-2中的正数转换为基数-2中的负数。 它可以通过维基百科的循环算法来完成。但是字节组替换要快得多。我已经实现了它,只是尝试优化它。

对于这种情况0111111,最终可以添加0。然后将应用规则。我们可以删除结果中的前导零。输出将是101010。

UPD2。

@WiktorStribiż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答案中的解决方案更快。

2 个答案:

答案 0 :(得分:3)

您可以使用简单的/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

请参阅online PHP demo

答案 1 :(得分:1)

回答问题

  

用于将基数-2中的正数转换为基数-2

中的负数的算法

我相信以下功能比正则表达式更有效:

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

参数是基数-2表示法中的正int60,例如11111011101。

该函数将参数转换为基数10,否定它,并将其转换回基数-2,如维基中所述:https://en.wikipedia.org/wiki/Negative_base#To_negabinary

适用于64位系统,但可以轻松采用32位工作。