php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #23298 Floating point data loss in serialize() (and sessions)
Submitted: 2003-04-21 15:22 UTC Modified: 2003-05-04 13:42 UTC
From: swbrown at ucsd dot edu Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: 4.3.2-RC OS: any
Private report: No CVE-ID:
 [2003-04-21 15:22 UTC] swbrown at ucsd dot edu
I ran into a bug in my code where the floating point number I put in a session variable changed slightly when it was loaded from the session the next time around, which in this case caused some math to differ by 1 depending on if the object had been through a session before.  This was definately not expected behavior, as I would expect data to be invariant under serialization.  I poked around at this for a bit, and I'm guessing that PHP uses serialize() to serialize session variables, and serialize() has data loss issues with float/double as it tries to convert them into truncated base 10 numbers.

Test case:

<?php
$var = 1.0 / 7.0;
$x = unserialize(serialize($var));
if($x != $var) print("FAIL\n");
else print("SUCCESS\n");
?>

One way I think this could be fixed is to add a new serialize field type other than 'd' for serialize()ing floats/doubles so that future PHP releases can serialize the entire float in base 16 or something so it won't alter data and won't break BC.  Maybe 'e' for IEEE or something.  Serialization should never alter the data being serialized, or it creates all sorts of funky problems (like mine where the object acts slightly different depending on if it's gone through a session).

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-04-23 11:47 UTC] sniper@php.net
php.ini option 'precision', when set high enough will let
this work as expected. (precision=18)

Here's a bit better example script that shows the problem:

<?php

ini_set("precision", 32);

$var = 1.4285714285714286476;
var_dump($var);
$foo = serialize($var);
echo '    ', $foo, "\n";
$x = unserialize($foo);
var_dump($x);

var_dump($x === $var);

ini_set("precision", 12);

$var = 1.4285714285714286476;
var_dump($var);
$foo = serialize($var);
echo '    ', $foo, "\n";
$x = unserialize($foo);
var_dump($x);

var_dump($x === $var);

?>

 [2003-04-23 11:48 UTC] sniper@php.net
Forgot the output:

# php test.php
float(1.4285714285714286475581502600107)
    d:1.4285714285714286031492292750045;
float(1.4285714285714286475581502600107)
bool(true)
float(1.42857142857)
    d:1.42857142857;
float(1.42857142857)
bool(false)

(notice the difference in the value in first part..)

 [2003-04-25 10:52 UTC] sniper@php.net
Here's another test script:

<?php

ini_set("precision", 32);

$var = 1.0 / 0.7;
echo "float($var)\n";
var_dump($var);

?>

Output:
-------
float(1.4285714285714286031492292750045)
float(1.4285714285714286475581502600107)

This all is most likely related to the serialize()
bug too.


 [2003-05-04 13:42 UTC] iliaa@php.net
This bug has been fixed in CVS.

In case this was a PHP problem, snapshots of the sources are packaged
every three hours; this change will be in the next snapshot. You can
grab the snapshot at http://snaps.php.net/.
 
In case this was a documentation problem, the fix will show up soon at
http://www.php.net/manual/.

In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites in short time.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Thu Apr 17 09:02:29 2014 UTC