【问题标题】:Large hex values with PHP hexdec使用 PHP hexdec 的大十六进制值
【发布时间】:2010-11-19 09:32:56
【问题描述】:

我有一些大的 HEX 值,我想显示为常规数字,我使用 hexdec() 转换为浮点数,我在 PHP.net 上找到了一个函数将其转换为十进制,但它似乎达到了天花板,例如:

$h = 'D5CE3E462533364B';
$f = hexdec($h);
echo $f .' = '. Exp_to_dec($f);

输出:1.5406319846274E+19 = 15406319846274000000

calc.exe 的结果 = 15406319846273791563

还有其他方法可以转换大的十六进制值吗?

【问题讨论】:

    标签: php hex


    【解决方案1】:

    正如hexdec manual page上所说:

    该函数现在可以转换值 对于平台来说太大了 整数类型,它会返回值 在这种情况下改为浮动。

    如果你想得到某种大整数(不是浮点数),你需要将它存储在一个字符串中。这可以使用BC Math 函数实现。

    例如,如果您查看 hexdec 手册页的 cmets,您会发现 this note

    如果您稍微调整一下该功能,以避免引起注意,您会得到:

    function bchexdec($hex)
    {
        $dec = 0;
        $len = strlen($hex);
        for ($i = 1; $i <= $len; $i++) {
            $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
        }
        return $dec;
    }
    

    (这个函数是从我链接的笔记中复制的;我只是稍微改编了一下)

    并在您的号码上使用它:

    $h = 'D5CE3E462533364B';
    $f = bchexdec($h);
    var_dump($f);
    

    输出将是:

    string '15406319846273791563' (length=20)
    

    所以,不是你拥有的那种大浮动;并且符合您的预期:

    calc.exe 的结果 = 15406319846273791563


    希望这有帮助;-)
    而且,是的,PHP 文档上的用户注释有时是一个真正的金矿;-)

    【讨论】:

    • 非常感谢。我已经安装了 BC Math,所以这得到了 GMP 解决方案的“答案”,但我确信两者都能胜任。谢谢:)
    【解决方案2】:

    hexdec() 当结果太大而无法表示为 int 时,会从 int 切换到 float。如果您想要任意长的值,您可能必须使用自己的转换函数将十六进制字符串更改为 GMP integer

    function gmp_hexdec($n) {
      $gmp = gmp_init(0);
      $mult = gmp_init(1);
      for ($i=strlen($n)-1;$i>=0;$i--,$mult=gmp_mul($mult, 16)) {
        $gmp = gmp_add($gmp, gmp_mul($mult, hexdec($n[$i])));
      }
      return $gmp;
    }
    
    print gmp_strval(gmp_hexdec("D5CE3E462533364B"));
    
    Output: 15406319846273791563
    

    【讨论】:

    • 我会将此设置为答案,但我没有安装 GMP 扩展(尽管也许我应该)。
    【解决方案3】:

    1.5406319846274E+19 是您号码的有限代表。您可以使用 printf() 获得更完整的文件

    printf("%u\n", hexdec($h));
    

    ...将输出“15406319846273792000”。 PHP 对如此大的数字使用浮点数,因此您可能会失去一点精度。如果你必须使用任意精度的数字,你可以试试bcmath extension。通过将十六进制分成两个 32 位字(这在大多数系统上应该是安全的),您应该能够获得更高的精度。例如:

    $f = bcadd(bcmul(hexdec(substr($h, 0, -8)), 0x100000000), hexdec(substr($h, 8)));
    

    ...将 $f 设置为 15406319846273791563。

    【讨论】:

    • 请注意这一点。这仅适用于 16 个字符的十六进制,任何较短的都会给出不正确的结果
    【解决方案4】:
    $num = gmp_init( '0xD5CE3E462533364B' ); // way to input a number in gmp
    echo gmp_strval($num, 10); // display value in decimal
    

    这是要使用的模块。将其转换为函数,然后用于您的数字。

    注意:将这些十六进制数字作为字符串提供:

    $num = "0x348726837469972346"; // set variable
    $gmpnum = gmp_init("$num"); // gmp number format
    echo gmp_strval($gmpnum, 10); // convert to decimal and print out
    

    【讨论】:

      【解决方案5】:

      将 HEX 转换为 DEC 很容易。但是,重建回十六进制数非常困难。 尝试使用base_convert ..

      $hexadecimal = base_convert(2826896153644826, 10, 16);
      // result: a0b0c0d0e0f1a
      

      【讨论】:

      • 至少在我的测试中 base_convert 仍在将其转换为我猜的浮点数。如果你运行 base_convert("9bdb999850d41000", 16, 10) 你得到 11230738975248618662 当真正的答案应该是 11230738975248617472
      【解决方案6】:

      在 MySQL 数据库中存储 64 位密钥时遇到此问题。使用一些二元运算符,我可以完美地转换为 64 位有符号整数(PHP 限制):(此代码比 bchexdec 函数快 16 倍,生成的变量平均使用一半的内存)。

      function x64toSignedInt($k){
          $left = hexdec(substr($k,0,8));
          $right = hexdec(substr($k,8,8));
          return (int) ($left << 32) | $right;
      }
      

      一般来说,MySQL 签名的 BIGINT 数据类型非常适合用作索引或存储。 HEX(column) 是一种在 SQL 查询中将其转换回 HEX 以在其他地方使用的简单方法。

      【讨论】:

        【解决方案7】:

        intval(var, base) 不处理吗?

        来自PHP Manual

        【讨论】:

        • var_dump(intval('D5CE3E462533364B', 16));让我 int 2147483647 ;不是他所期望的^^;请参阅有关 intval 文档的注释,其中说:“最大值取决于系统。32 位系统的最大有符号整数范围为 -2147483648 到 2147483647。例如在这样的系统上,intval('1000000000000')将返回 2147483647。”
        猜你喜欢
        • 1970-01-01
        • 2015-06-25
        • 2018-07-26
        • 2019-12-01
        • 2013-03-10
        • 1970-01-01
        • 2012-11-18
        • 1970-01-01
        相关资源
        最近更新 更多