PHP - 序列化浮点(PHP - Serialize floating points)

2019-06-25 13:52发布

我生成6,8(均为有很好的理由)之间10个随机浮动,并在一个序列化的形式将它们写入到MySQL数据库。 但一个怪癖,似乎在存储时出现:

存储之前我只是在输出相同的数据,看看是什么样子,这是结果我得到

a:10:{i:0;d:6.20000000000000017763568394002504646778106689453125;i:1;d:7.5999999999999996447286321199499070644378662109375;i:2;d:6.4000000000000003552713678800500929355621337890625;..}

正如你所看到的,我越来越长的数字像6.20000000000000017763568394002504646778106689453125什么,而不是我真的很喜欢看到的,只是6.2。 当我序列数据,如果我只输出数组,我得到的花车到小数点后一位,这是唯一的发生。 这里是我的代码:

function random_float ($min,$max) {
   return ($min+lcg_value()*(abs($max-$min)));
}

$a1 = random_float(6, 8);
$a1 = round($a1, 1);
$a2 = random_float(6, 8);
$a2 = round($a2, 1);    
$a3 = random_float(6, 8);
$a3 = round($a3, 1);
    ...
$array = array($a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9, $a10);

echo serialize($array);

Answer 1:

像6.2数量不能准确地使用浮点数学中的计算机,因为是它没有有限碱基2表示来表示。 什么,当你看到echo -ing数量的东西供人阅读,因此,值将四舍五入到什么可浮动的准确性提供(约6小数位为32位和17对64位浮点值)。

当序列化这些值,但是,你真正想要的确切值(即所有位是在那里),而不只是最近的“好”的价值。 可能有一个以上的浮点/双精度表示,其计算结果为约6.2和序列化时,你通常真想存储他精确值给你,以便正确地恢复它们拥有的是最后一位。 这就是为什么你的价值观越来越荒谬“精度”在那里。 这一切都只是保持你开始使用什么确切位表示。

但是,为什么你到底要到严格控制序列化输出? 我的意思是,它只是有这样您就可以往返你的数据结构和读回在后面。 你肯定不希望的地方使用序列化表示在输出人类左右。 所以,如果它只是“好看的”的价值观,你不应该使用序列化它有一个完全不同的目的。



Answer 2:

并将其作为使用后的字符串number_format :

$number = number_format($float, 2);


Answer 3:

只是减少精度:

ini_set('serialize_precision',2);


Answer 4:

并将其作为整数(由10乘以它在转移点的前小数点后第一位),并将其转换回来,如果你需要它:

function random_float($min,$max) {
    return ($min+lcg_value()*(abs($max-$min)));
}

$array = array();
for ($i=0; $i<10; $i++) {
    $array[] = (int) round(random_float(6, 8) * 10);
}
$serialized = serialize($array);
var_dump($serialize);

$array = unserialize($serialized);
foreach ($array as $key => $val) {
    $array[$key] = $val / 10;
}
var_dump($array);


Answer 5:

下面是我采取的甘博的回答。 我把IteratorAggregate上有那么这将是的foreach可以,但你可以添加可数名词和ArrayAccess接口也。

<?php

class FloatStorage implements IteratorAggregate
{
  protected $factor;
  protected $store = array();

  public function __construct( array $data, $factor=10 )
  {
    $this->factor = $factor;
    $this->store = $data;
  }

  public function __sleep()
  {
    array_walk( $this->store, array( $this, 'toSerialized' ) );
    return array( 'factor', 'store' );
  }

  public function __wakeup()
  {
    array_walk( $this->store, array( $this, 'fromSerialized' ) );
  }

  protected function toSerialized( &$num )
  {
    $num *= $this->factor;
  }

  protected function fromSerialized( &$num )
  {
    $num /= $this->factor;
  }

  public function getIterator()
  {
    return new ArrayIterator( $this->store );
  }
}

function random_float ($min,$max) {
   return ($min+lcg_value()*(abs($max-$min)));
}

$original = array();
for ( $i = 0; $i < 10; $i++ )
{
  $original[] = round( random_float( 6, 8 ), 1 );
}

$stored = new FloatStorage( $original );

$serialized = serialize( $stored );
$unserialized = unserialize( $serialized );

echo '<pre>';
print_r( $original );
print_r( $serialized );
print_r( $unserialized );
echo '</pre>';


Answer 6:

对我来说,我发现了3种方式:

  1. 转换浮子整数浮子变种乘以一个大数目(例如1,000,000)之后; 它不是在它的使用,你不应该忘记同样百万它把一个非常方便的方法
  2. 使用preg_replace('/d:([0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)?);/e', "'d:'.((float)$1).';'", $value); 其中$值是您的浮动; 发现这里
  3. 也,圆由浮子轮()并将其存储在数组作为字符串。

在任何情况下,我使用的变体#2



Answer 7:

铸造适用 ,并且它更快 ,例如:

$a = 0.631;
$b = serialize($a);
$c = serialize((string)$a);
var_dump($b);

串(57) “d:0.6310000000000000053290705182007513940334320068359375;”

var_dump($c);

串(12)的 “S:5:” 0.631 “;”

var_dump(unserialize($b));

浮动(0.631)

var_dump(unserialize($c));

串(5) “0.631”

最重要的是要投其重新打开反序列化:

var_dump((float)unserialize($c));

浮动(0.631)



Answer 8:

php.ini文件包含serialize_precision指令,它允许您控制多少显著数字将被系列化的浮动。 在你的情况下,存储只是一个6之间的数字的十进制到8意味着两个显著数字。

您可以在php.ini文件直接在脚本中设置此设置或:

ini_set('serialize_precision', 2);

如果你不关心的显著数字的确切人数,但关心不具有从浮点数的存储方式产生的数字组成的意大利面条,你也可以给一去到值-1,这将调用“特殊舍入算法”,这很可能是究竟需要做什么:

ini_set('serialize_precision', -1);

你甚至可以重新回您的序列后,其原始值:

    $prec = ini_get('serialize_precision');
    ini_set('serialize_precision', -1);

    ... // your serialization here

    ini_set('serialize_precision', $prec);


Answer 9:

在php.ini中设置你的serialize_precision值为-1将解决浮点问题,或者你可以将其设置为您喜欢的,按照这里的规格值: http://php.net/manual/en/ini。 core.php中#ini.serialize精

PHP版本<= 5.3.5附带的“100”的默认值,而默认现在是7.0.33版本是“17”,虽然与你的发行版捆绑包可能已附带“-1”

正如在其他答复中指出,可以覆盖在应用程序本身这个设置甚至定制的php.ini,你的虚拟主机容器或指定的.htaccess。

我希望帮助:)



文章来源: PHP - Serialize floating points