我生成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,000,000)之后; 它不是在它的使用,你不应该忘记同样百万它把一个非常方便的方法
- 使用
preg_replace('/d:([0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)?);/e', "'d:'.((float)$1).';'", $value);
其中$值是您的浮动; 发现这里 - 也,圆由浮子轮()并将其存储在数组作为字符串。
在任何情况下,我使用的变体#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