在PHP中将值数组转换为单个浮点数?

3

我有一个数组,包含以下数值(当使用print_r();函数打印该数组时):

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

十六进制中的值为:

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

我想做的是将这个由四个字节组成的数组转换为浮点数值。如果我使用implode() 将数组转换为值,它只会将字符串合并为66233204205,而不是类似于0x42E9CCCD的值。 因此,我无法使用floatval() 。PHP对我来说是新东西,使用字符串值代替实际位(在C中可以这样做)也是如此。

我的想法是以某种方式使用十六进制值来implode() 它,而不是那些整数数字,然后使用floatval()

有任何想法吗?

编辑:

只是让它更清楚一些,我应该得到结果为116.900


你是想对数组的值求和还是将它们一个接一个地追加到数组中? - Goldbug
@Goldbug,非常感谢您的快速回复!我想将数组的值一个接一个地附加在一起(以十六进制形式),然后将其转换为浮点数。如果我使用 implode(); 进行附加,它会将其附加在字符串值中;这看起来像是 66233204205 - Rayaarito
听起来像是 array_map('dechex', $array),然后是 implode(),最后是 hexdec()。但我没有测试过,我认为对于更大的数字它会失败。 - jh1711
1
感谢@slevy1。我可能过于关注0x42E9CCC字符串,没有意识到它并没有让我们更接近解决方案。至少编辑是在我的评论几分钟后 :) - jh1711
4个回答

2

你需要进行简单的数学运算,将数组中的十六进制值依次连接起来。该算法应该是这样的:

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

    // 假设$array是您的原始数组
    $concat = $array[0];
    $count = count($array);
    for($i = 1; $i < $count; $i++){
        $concat =  ($concat << 8) + $array[$i];
    }
    
    // 显示连接的十六进制值:42e9cccd
    var_dump(dechex($concat));
    
    // 现在对连接的十六进制值进行操作
    
这是一个演示,https://eval.in/844793

1
该函数将数组的值(以十六进制形式)附加在一起。使用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

1

使用修订后的答案....

在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);

请看演示

该代码试图通过将0添加到$temp中的值来为十六进制字符串提供数学上下文。这段代码在PHP 7之前有效,因为有关部门确定十六进制字符串带来了比它们值得的更多问题;请参见此RFC和手册:{{link3:“十六进制字符串不再被认为是数字”}}。

连接作为一个字符串操作,创建了示例的十六进制字符串,其直接使用在数学运算中证明是不明智的。在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);    

查看 演示

如果您使用带有指定参数的 filter_var(),PHP 将识别 array_reduce() 产生的数字十六进制字符串。这样,您可以获得一个评估为 1122618573 的整数。关键不是整数的,而是其二进制位模式。借鉴官方答案此处,代码需要将 $int 打包成二进制字符串,然后将其作为浮点数unpack -- 几乎。该结果将作为只有一个元素的数组返回。在弹出并捕获该元素的浮点值后,printf() 显示 116.900


1
非常感谢您提供如此详细的回复。当我尝试运行它时,由于我正在64位机器上运行,它显示了1122618573值。有没有什么方法可以避免这种情况,以显示其真正预期的值116.900?其他答案能够显示116.900,这很奇怪,考虑到我正在64位机器上运行。 - Rayaarito
@Rayaarito:回答你的问题,是的,有一个解决方法;请查看我的更新答案。 - slevy1
1
感谢这个解决方法。我之前使用了其他方法,只是因为它对我所使用的版本有效,并且我已经将其放入了我的代码中。但是,我标记了你的答案是正确的,因为它是“未来可靠”的。所以当人们以后来到这个问题时,他们会知道你的答案无论如何都可以工作,因为它是针对最新的 PHP 7.1.8 版本的。谢谢! - Rayaarito

0

您没有说明数组是否表示整数,是否为浮点值的整数部分,或者是否以IEEE 754格式表示整个数字。 无论如何,我建议您查看“pack”函数。

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

在这里你可以找到文档:基本上,你需要提供你想要获取的类型以及相应的值。 此外,PHP不是一种强类型语言,所以你不必区分整数和浮点数。你可以像处理浮点数一样处理整数,反之亦然。但如果你想要100%确定,只需像这样做:

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接