10

我需要一个base_convert()从 2 到 62 的函数,但我缺少我需要使用的数学,我知道由于 PHP 的限制,我需要使用 bcmath,这很好。

像这样的函数将一个数字从基数 10 转换为另一个基数,最高可达 62,但我想实现相同的功能base_convert(),例如:一个可以在任意基数之间转换的函数。

我找到了一个似乎可以做到这一点的函数,但它给我的感觉是有一些冗余和缓慢的代码,如果我知道德语,我想稍微调整一下,但我不知道。=(

这是该函数的可读性更高的版本:

function bc_base_convert($value, $quellformat, $zielformat)
{
    $vorrat = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    if (min($quellformat, $zielformat) < 2)
    {
        trigger_error('Bad Format min: 2', E_USER_ERROR);
    }

    if (max($quellformat, $zielformat) > strlen($vorrat))
    {
        trigger_error('Bad Format max: ' . strlen($vorrat), E_USER_ERROR);
    }

    $dezi = '0';
    $level = 0;
    $result = '';
    $value = trim(strval($value), "\r\n\t +");
    $vorzeichen = '-' === $value{0} ? '-' : '';
    $value = ltrim($value, "-0");
    $len = strlen($value);

    for ($i = 0; $i < $len; $i++)
    {
        $wert = strpos($vorrat, $value{$len - 1 - $i});

        if (FALSE === $wert)
        {
            trigger_error('Bad Char in input 1', E_USER_ERROR);
        }

        if ($wert >= $quellformat)
        {
            trigger_error('Bad Char in input 2', E_USER_ERROR);
        }

        $dezi = bcadd($dezi, bcmul(bcpow($quellformat, $i), $wert));
    }

    if (10 == $zielformat)
    {
        return $vorzeichen . $dezi; // abkürzung
    }

    while (1 !== bccomp(bcpow($zielformat, $level++), $dezi));

    for ($i = $level - 2; $i >= 0; $i--)
    {
        $factor = bcpow($zielformat, $i);
        $zahl = bcdiv($dezi, $factor, 0);
        $dezi = bcmod($dezi, $factor);
        $result .= $vorrat{$zahl};
    }

    $result = empty($result) ? '0' : $result;

    return $vorzeichen . $result;
}

谁能解释我上面的函数或者给我一些关于任意基数之间直接转换过程的说明?

4

6 回答 6

15

从 PHP 5.3.2 开始,bc_math 和 gmp 现在都支持高达 62 的基数,所以你可以这样做:

echo gmp_strval(gmp_init($mynumber, $srcbase), $destbase);

或 bc_math 等价物。

于 2011-08-10T16:17:36.207 回答
9

请不要问我从哪里得到它,我只是记得它基于我在网上找到的一些例子......

  function charset_base_convert ($numstring, $fromcharset, $tocharset) {
     $frombase=strlen($fromcharset);
     $tobase=strlen($tocharset);
     $chars = $fromcharset;
     $tostring = $tocharset;

     $length = strlen($numstring);
     $result = '';
     for ($i = 0; $i < $length; $i++) {
         $number[$i] = strpos($chars, $numstring{$i});
     }
     do {
         $divide = 0;
         $newlen = 0;
         for ($i = 0; $i < $length; $i++) {
             $divide = $divide * $frombase + $number[$i];
             if ($divide >= $tobase) {
                 $number[$newlen++] = (int)($divide / $tobase);
                 $divide = $divide % $tobase;
             } elseif ($newlen > 0) {
                 $number[$newlen++] = 0;
             }
         }
         $length = $newlen;
         $result = $tostring{$divide} . $result;
     }
     while ($newlen != 0);
     return $result;
  }
于 2011-01-12T12:10:02.557 回答
1

对于任何翻译问题,从数字基础到人类语言,最简单的方法是通过中间格式进行翻译。

function bc_base_convert($num, $from, $to) {
    return bc_convert_to(bc_parse_num($num, $from), $to);
}

现在你需要写的是bc_convert_tobc_parse_num。如果平台区分数字类型,您需要考虑到这一点。此外,浮点数需要特别考虑,因为一个数字可能在一个基数中具有有限表示,但不是另一个(例如 1/3 是 0.1 3但 0.333... 10,而 1/10 10是 .0001100110011... 2)。

至于转换如何工作的一般解释,请考虑位置基础系统如何工作。以b为底的“a n a n-1 ...a 1 a 0 ”形式的数字表示数字“a n *b n + a n-1 *b n-1 + ... + a 1 *b 1 + a 0 *b 0 "。转换基本上是通过在另一个基础 β 的上下文中评估表达式来工作的。

于 2009-12-21T03:42:57.657 回答
1

我在互联网上找到的大多数示例以及此答案中的示例都使用了 BC 数学函数。如果你不想使用 BC 数学函数,你可以看看这个库: http ://www.lalit.org/lab/base62-php-convert-number-to-base-62-for-short -网址/

  • 它不使用 BC Math 函数,因此无需使用 BC Math 库即可工作。
  • 当基数低于 36 时,它使用本机 base_convert 函数以加快执行速度。
  • 输出数字向后兼容本机 base_convert 函数。
  • 可用于在 2-64 之间转换任意基数。
于 2011-12-08T11:49:42.877 回答
0

我在这里写了关于使用 BCMath 函数进行十进制/二进制转换的文章:http ://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ 。您可以轻松地修改该代码以转换为不同的基础。

例如,在转换整数的情况下,修改例程 dec2bin_i() 和 bin2dec_i()。重命名它们并添加一个基本参数——类似于 dec2base_i($base,$decimal_i) 和 base2dec_i($base,$num_i),将硬编码的“2”更改为变量 $base,将数字余数转换为/从字符基础,并重命名变量。

现在,要在任意基数之间进行转换,请使用小数作为中间值并调用这两个新函数。例如,通过调用 $dec = base2dec_i('42','123') 后跟 $b59 = dec2base_i(59,$dec) 将基数为 42 的数字“123”转换为基数 59。

(您也可以创建一个在一次调用中完成的组合函数。)

于 2009-12-21T14:29:43.873 回答
-1

如果可能,此函数输出与GNU Multiple Precision相同...</p>

<?php

function base_convert_alt($val,$from_base,$to_base){
static $gmp;
static $bc;
static $gmp62;
if ($from_base<37) $val=strtoupper($val);
if ($gmp===null) $gmp=function_exists('gmp_init');
if ($gmp62===null) $gmp62=version_compare(PHP_VERSION,'5.3.2')>=0;
if ($gmp && ($gmp62 or ($from_base<37 && $to_base<37)))
return gmp_strval(gmp_init($val,$from_base),$to_base);
if ($bc===null) $bc=function_exists('bcscale');
$range='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($from_base==10)
$base_10=$val;
else
{
$n=strlen(($val="$val"))-++$ratio;
if ($bc) for($i=$n;$i>-1;($ratio=bcmul($ratio,$from_base)) && $i--)
$base_10=bcadd($base_10,bcmul(strpos($range,$val[$i]),$ratio));
else for($i=$n;$i>-1;($ratio*=$from_base) && $i--)
$base_10+=strpos($range,$val[$i])*$ratio;
}
if ($bc)
do $result.=$range[bcmod($base_10,$to_base)];
while(($base_10=bcdiv($base_10,$to_base))>=1);
else
do $result.=$range[$base_10%$to_base];
while(($base_10/=$to_base)>=1);
return strrev($to_base<37?strtolower($result):$result);
}


echo base_convert_alt('2661500360',7,51);

// Output Hello
于 2017-03-08T20:33:32.633 回答