【问题标题】:Convert array of values into a single float value in PHP?在PHP中将值数组转换为单个浮点值?
【发布时间】:2017-08-17 18:39:16
【问题描述】:

我有一个包含这些值的数组(当使用print_r(); 打印数组时

Array:
[0] => 66 
[1] => 233
[2] => 204
[3] => 205

十六进制值是:

Array:
[0] => 0x42 
[1] => 0xE9
[2] => 0xCC
[3] => 0xCD

我要做的是把这个 4 字节数组变成一个浮点值。如果我使用implode(); 将数组转换为一个值,它只是将字符串组合成66233204205,而不是不相似的0x42E9CCCD。因此我不能使用floatval()。 PHP 对我来说是新的,所以使用字符串值而不是实际位,就像我在 C 中一样。

我在想的是如何implode() 它使用十六进制值,而不是那些整数,然后使用floatval()

各位有什么想法吗?

编辑:

只是这样更清楚一点,我应该得到116.900作为结果

【问题讨论】:

  • 您是要对这些值求和还是只是将数组的值一个接一个地追加?
  • @Goldbug,感谢您这么快的回复!我希望在下一个(十六进制)之后附加数组的值,然后将其转换为浮点数。如果我使用implode(); 附加它,它会将它附加到它的字符串值中;看起来像66233204205
  • 听起来像array_map('dechex', $array),然后是implode(),然后是hexdec()。但我没有测试它,我认为它会因更大的数字而失败。
  • 谢谢@slevy1。我必须专注于0x42E9CCC 字符串,却没有意识到它并没有让我们更接近解决方案。至少在我发表评论几分钟后进行了编辑:)

标签: php arrays floating-point


【解决方案1】:

你必须做一个简单的数学运算来一个接一个地连接数组的十六进制值。算法是这样的:

  • 将数组的第一个十六进制值分配给结果变量,在本例中为 $concat
  • 使用for 循环从第二个元素到第n 个元素循环遍历数组
  • 在循环的每次迭代中,将结果变量的现有十六进制值左移 8 倍,并将新的十六进制值放在结果变量的最低有效 8 位中。

    // Suppose $array is your original array
    $concat = $array[0];
    $count = count($array);
    for($i = 1; $i < $count; $i++){
        $concat =  ($concat << 8) + $array[$i];
    }
    
    // display concatenated hex value: 42e9cccd
    var_dump(dechex($concat));
    
    // Now do your operation on the concatenated hex value
    

这是一个演示,https://eval.in/844793

【讨论】:

    【解决方案2】:

    修改后的答案 ....

    使用十六进制字符串执行数学运算曾经是 PHP 支持的一项功能。现在在 PHP 7 中,十六进制字符串仅表示字符串,不再被识别为包含数值。如果你试图用它做数学,结果为零。考虑以下代码:

     <?php  
    
     $arr = [66, 233, 204, 205];
    
     $res = array_reduce( $arr, function($c,$i) {
                       $c.=dechex( $i );
                       return $c;
     });
    
     $temp = "0x" . $res;  // 0x42e9cccd
     var_dump($temp + 0);
    

    demo

    此代码尝试通过将零添加到 $temp 中包含的值来为十六进制字符串提供数学上下文。此代码在 PHP 7 之前一直有效,因为确定 hexstrings 的权力造成的问题多于其价值;请参阅此RFC 和手册:"Hexadecimal strings are no longer considered numeric"

    作为字符串运算的串联创建示例的十六进制字符串,其直接使用在数学运算中被证明是不明智的。将发出通知(在 PHP 7.1 中),抱怨如下:

    注意:遇到格式不正确的数值

    您可以禁止显示此通知,但在 PHP 7 中生成的总和将为零。当代码在 PHP 5.6 中正确运行时,1122618573 的结果似乎是错误的,肯定太大而无法转换为浮点数并获得OP 寻求的价值。

    ...真正的解决方法

        <?php
    
    
        $arr = [66, 233, 204, 205];
        $res = array_reduce( $arr, function($c,$i) {
                           $c.=dechex( $i );
                           return $c;
        });
        $temp = "0x" . $res;
        $int = filter_var( $temp, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX );
        if (false === $int) {
            throw new Exception("Invalid integer!");
        }
    
    
        $arr = (unpack('f', pack('i', $int )));
        $f = array_pop($arr);
        printf("%.3f",$f);    
    

    demo

    如果您使用带有指定参数的 filter_var(),PHP 将识别 array_reduce() 产生的数字十六进制字符串。通过这种方式,您可以获得一个整数,其值为1122618573。关键是它的二进制位模式,而不是整数的。借用官方答案here,代码需要将pack $int 转换为二进制字符串,随后将unpack 作为浮点数——差不多。该结果将作为只有一个元素的数组返回。在弹出并捕获该元素的浮点值后,printf() 显示116.900

    【讨论】:

    • 感谢您提供如此详细的回复。当我试一试时,它会显示 1122618573 值,因为我在 64 位机器上运行。有没有办法让它显示其真正的预期价值116.900?其他答案能够显示 116.900。考虑到我在 64 位机器上,这很奇怪。
    • @Rayaarito:回答你的问题,是的,有一个变通方法;请查看我的更新答案。
    • 感谢您的工作。我确实使用了其他的,只是因为它适用于我拥有的版本并且我已经将它放在我的代码中。但是,我标记你的正确,因为它是“面向未来的”。因此,当人们稍后提出这个问题时,他们知道您的答案无论如何都会起作用,因为它适用于最新一代的 PHP。在撰写本文时,它是 v 7.1.8。谢谢!
    【解决方案3】:

    这会将数组的值相互附加(以十六进制表示)。 PHP 的 dechex() 函数。

    http://php.net/dechex

    dechex — 十进制转十六进制

    $b = [66,233,204,205];
    $a = dechex($b[0]);
    for($x = 1; $x < count($b); $x++) {
        $a = $a . dechex($b[$x]);
    }
    echo $a; // $a = 42e9cccd
    

    【讨论】:

      【解决方案4】:

      您没有指定您的数组是表示整数、是浮点值的整数部分还是以 IEEE 754 格式表示的整数。 无论如何,我建议你看一下“打包”功能。

      $value = pack('i', your_value);
      

      HERE 你可以找到文档:基本上你必须提供你想要获得的类型,当然还有你的值。 此外,PHP 不是一种强类型语言,因此在这种情况下,您不必区分整数和浮点数。您可以将整数视为浮点数,反之亦然。但是,如果您想 100% 确定,只需执行以下操作:

      $value = floatval(pack('i', your_value));
      

      当然,这取决于机器,但我不知道任何运行 PHP 的机器不使用 IEEE 754 浮点数。

      【讨论】:

        猜你喜欢
        • 2021-07-16
        • 2018-02-22
        • 2013-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-10
        • 1970-01-01
        相关资源
        最近更新 更多