【问题标题】:Converting binary array to decimal string strange behaviour将二进制数组转换为十进制字符串奇怪的行为
【发布时间】:2014-06-21 22:08:28
【问题描述】:

我目前在php中使用int[]数组实现左移,需要在操作后取回小数。所以我写了以下sn-p来尝试将二进制数组转换为十进制。

function bin2dec($bin)
{
    $length = count($bin) - 1;
    $sum = 0;
    //convert using doubling
    for($i = 0; $i < $length; $i++)
    {
        //use string_add if doubling bigger than int32
        if($i >= 16)
        {
            $double = $this->string_add("$sum", "$sum");
            $cr = $bin[$i];
            if($cr == 0)
            {
                $sum = $this->string_add($sum, $double);
            }
            else{
                return $i;//WHAT's UP??!
                $add = $this->string_add($double, "$cr");
                $sum = $this->string_add($sum, $add);
            }
        }
        else{
            $sum += ($sum * 2) + $bin[$i];
        }
    }
    return $sum;
}

现在奇怪的问题出在循环中,$cr != 0$i 返回了一个已经不满足循环条件的令人难以置信的值,但我不知道为什么会这样。这是其余的相关代码。

function string_add($a, $b)
{
    $lena = strlen($a); $lenb = strlen($b);
    if($lena == $lenb)
    {
        $len = $lena - 1;//any
    }
    else if($lena > $lenb)
    {
        $b = str_pad($b, $lena, "0", STR_PAD_LEFT);
        $len = $lena - 1;
    }
    else if($lenb > $lena){
        $a = str_pad($a, $lenb, "0", STR_PAD_RIGHT);
        $len = $lenb - 1;
    }
    $result = "";
    for ($i = $len, $carry = 0; $i >= 0 || $carry != 0; $i--)
    {
        $add1 = $i < 0 ? 0 : $a[$i];
        $add2 = $i < 0 ? 0 : $b[$i];
        $add = $add1 + $add2 + $carry;
        if ($add > 9) {
            $carry = 1;
            $add -= 10;
        }
        else {
            $carry = 0;
        }
        $result .= $add;
    }
    return strrev($result);
}

$arr = array_pad(array(1), 62, 0);
$dec = bin2dec($arr);
return $dec;//test

我还实现了working version on ideone for testing。有谁明白为什么会这样?

谢谢。

【问题讨论】:

  • 我不知道PHP,但我知道C。我的问题是,这真的是C 还是相关的,或者只是被错误地标记了?
  • @ThoAppelsin,PHP 基于 C,所以我认为这可能是内部问题/错误。
  • 你在使用string_add时也有类似的问题。基本上,在这两种情况下,$sum 都是三倍,而不是两倍。
  • ooga 所说的,据我所知,$length = count($bin) - 1; 行也应该没有- 1。虽然它看起来有点熟悉,但对于像 countstring_add 这样的内置函数,这对我来说是个问题。此外,按照这种逻辑,每个PHP 问题也可能会被自动标记为C
  • 天啊,非常感谢@ooga 和@ThoAppelsin。所以这些实际上是问题的原因,加上我在 bin2dec 中遇到了同样的问题(产生双倍并再次加到总和)。我以为我得到的奇怪的“返回值”实际上是因为 $cr 从来都不是 1。将发布工作代码。

标签: php c arrays memory int


【解决方案1】:

好的,显然 问题 是在 bin2dec 中添加了多余的内容,并且不必要地从长度中减去了 1。这是最终的工作版本:

<?php
class MyClass{
    function bin2dec($bin)
    {
        $length = count($bin);
        $sum = 0;
        //convert using doubling
        for($i = 0; $i < $length; $i++)
        {
            //use string_add if doubling bigger than int32
            if($i >= 16)
            {
                $sum = $this->string_add("$sum", "$sum");
                $cr = $bin[$i];
                if($cr != 0){
                    $sum = $this->string_add($sum, "$cr");
                }
            }
            else{
                $sum += $sum + $bin[$i];
            }
        }
        return $sum;
    }

    function string_add($a, $b)
    {
        $lena = strlen($a); $lenb = strlen($b);
        if($lena == $lenb)
        {
            $len = $lena - 1;//any
        }
        else if($lena > $lenb)
        {
            $b = str_pad($b, $lena, "0", STR_PAD_LEFT);
            $len = $lena - 1;
        }
        else if($lenb > $lena){
            $a = str_pad($a, $lenb, "0", STR_PAD_RIGHT);
            $len = $lenb - 1;
        }
        $result = "";
        for ($i = $len, $carry = 0; $i >= 0 || $carry != 0; $i--)
        {
            $add1 = $i < 0 ? 0 : $a[$i];
            $add2 = $i < 0 ? 0 : $b[$i];
            $add = $add1 + $add2 + $carry;
            if ($add > 9) {
                $carry = 1;
                $add -= 10;
            }
            else {
                $carry = 0;
            }
            $result .= $add;
        }
        return strrev($result);
    }
}

$man = new MyClass();
$arr = array_pad(array(1), 62, 0);
$dec = $man->bin2dec($arr);
echo $dec;

【讨论】:

    【解决方案2】:

    使用字符串...

    function bin2dec($bin)
    {
        $length = count($bin);
        $sum = "";
        for ( $i = 0; $i < $length; $i++)
        {
            $sum = $sum . ( $bin[$i} == 0 ? '0' : '1');
        }
        return $sum;
    }
    
    function string_add($a, $b)
    {
        // not efficient, but obvious
        $maxlen = ( strlen($a) > strlen($b) ? strlen($a) : strlen($b);
    
        // make them both same length as longest
        $a = str_pad($a, $maxlen, "0", STR_PAD_LEFT);
        $b = str_pad($b, $maxlen, "0", STR_PAD_LEFT);
        $result = "";
        $carry = 0;
    
        // start from the right end
        for ($i = $maxlen - 1; $i >= 0; $i--)
        {
            $val = $a[$i] + $b[$i] + $carry;
            $result = ( $val % 10 ) . $result;
            $carry = $val / 10;
        }
    
        // handle final carry if present
        if ( $carry > 0 )
        {
            $result = $carry . $result;
        }
    
        return $result;
    }
    
    $arr = array_pad(array(1), 62, 0);
    $dec = bin2dec($arr);
    return $dec;//test
    

    【讨论】:

    • 多次出错。在(可能)添加1 之前,您应该将$sum 加倍。他正在尝试制作一个程序,该程序适用于他认为大于最大整数的数字。因此,他的尝试和string_add 函数的复杂性。
    • &amp;bin 成为[1, 0, 1]。在第一个循环结束时,$sum 将是 2,然后是 4,然后是 10,这是不正确的。将$sum = $sum * 2; 行切换到上面的 4 行可以解决问题,但我不明白为什么我们不应该直接不使用$sum = 2 * $sum + $bin[$i];
    最近更新 更多