Php 64位浮点文本

Php 64位浮点文本,php,long-integer,literals,pack,double-precision,Php,Long Integer,Literals,Pack,Double Precision,我试图在php中将64位浮点转换为64位整数(并返回)。我需要保留字节,所以我使用pack和unpack函数。我要寻找的功能基本上是Java的Double.doubleToLongBits()方法 在php文档for pack()上的注释的帮助下,我成功地做到了这一点: 100000000 1.1710299640683E-305 但这是它变得棘手的地方 echo decode(1.1710299640683E-305); -662957122597708544 我不知道这里出了什么问题。自己

我试图在php中将64位浮点转换为64位整数(并返回)。我需要保留字节,所以我使用pack和unpack函数。我要寻找的功能基本上是Java的Double.doubleToLongBits()方法

在php文档for pack()上的注释的帮助下,我成功地做到了这一点:

100000000

1.1710299640683E-305

但这是它变得棘手的地方

echo decode(1.1710299640683E-305);
-662957122597708544

我不知道这里出了什么问题。自己试试看:

linux上需要64位PHP。此站点似乎模拟了该设置:

。。。永远不要相信 浮点数结果到最后一位,不比较浮点数 点数直接表示相等。如果需要更高的精度, 任意精度的数学函数和gmp函数是 可用。有关“简单”的解释,请参阅»浮点指南 这也叫做“为什么我的数字加起来不算?”


它工作正常,这种情况下唯一的问题是逻辑:

echo decode(1.1710299640683E-305);
您不能使用echo函数的“四舍五入”和“人类可读”输出来解码原始值(因为您正在失去此双精度)

如果您将encode(100000000000)的返回保存到变量中,然后再次尝试对其进行解码,它将正常工作(您可以在100000000000上使用echo,而不会丢失精度)

请参见下面的示例,您也可以在其上执行:


如果你有一个可靠的固定小数点,就像我的例子和货币的例子一样,你可以将你的浮动乘以10的某个幂(例如,美元是100)

然而,这对大量的人来说是行不通的,也不能正式解决这个问题。
在php 5.4中,似乎不可能在不丢失原始整数值的情况下将整数转换为浮点字符串再转换回来。您的答案并不能解决我的问题。注意
1.1710299640683E-305==1.1710299640683E-305
返回true您正在比较两个直接定义的浮点值,这当然是相等的。但是,如果将解码方法返回的浮点与直接定义的浮点进行比较,则由于链接中解释的原因,这些浮点将不相等。如果两个浮点具有相同的二进制表示形式,则它们应该相等,无论它们是否以相同的方式定义。我想做的就是在不改变位的情况下将long转换为double…如何在不损失精度的情况下获得
encode(100000000000)
的字符串表示形式?在PHPSetting
precision=200
in
php.ini
中,这必须是可能的。您可以尝试使用
printf('.200f',$encoded)但php无论如何都会将其截断为53。您甚至应该得到通知:“请求的200位精度在(..)中被截断为PHP最大53位”。因此,您将无法使用标准的php解决方案(尽管可能有一些自定义库!)。请问您需要它做什么?我想利用我的redis zset分数的所有64位。似乎predis故意失去了精确性。所以问题是该值与encode(…)值不同,即使它看起来是这样的<代码>回波编码(100000000000)-1.1710299640683E-305;//2.3525429792377E-319
所以问题是,您希望字符串100%准确吗?是的。想法是你可以来回转换。你会对一个丑陋的解决方案感兴趣吗?基本上,如果您使用encode函数的结果,并将差异添加到末尾(例如1.171029964068323525429792377E-305),则表示“相等”。但是,更改最右边的数字也会导致“相等”。
echo encode(10000000000000);
echo decode(1.1710299640683E-305);
$x = encode(10000000000000);
var_dump($x); //float(1.1710299640683E-305)
echo decode($x); //10000000000000

$y = (float) "1.1710299640683E-305";
var_dump($y); //float(1.1710299640683E-305)
echo decode($y); //-6629571225977708544 

$z = ($x == $y);
var_dump($z); //false
echo decode(1.1710299640683E-305);
<?php
    function encode($int) {
        $int = round($int);

        $left = 0xffffffff00000000;
        $right = 0x00000000ffffffff;

        $l = ($int & $left) >>32;
        $r = $int & $right;

        return unpack('d', pack('NN', $l, $r))[1];
    }

    function decode($float) {
        $set = unpack('N2', pack('d', $float));
        return $set[1] << 32 | $set[2];
    }

    echo decode(encode(10000000000000)); // untouched
    echo '<br /><br />';

    $encoded = encode(10000000000000);
    echo $encoded; // LOOSING PRECISION! 
    echo ' - "human readable" version of encoded int<br /><br />';

    echo decode($encoded); // STILL WORKS - HAPPY DAYS!
?>
function encode($float) {
     return (int) $float * pow(10, 2);
}
function decode($str) {
    return bcdiv($str, pow(10, 2), 2);
}