php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78688 Invalid float serialization
Submitted: 2019-10-18 11:33 UTC Modified: 2019-10-18 12:51 UTC
From: eirik at nymedia dot no Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.3.10 OS: Linux/OSX
Private report: No CVE-ID: None
 [2019-10-18 11:33 UTC] eirik at nymedia dot no
Description:
------------
I noticed when encoding a json object that the float 440.0 was not encoded correctly. So I looked into it, and when the float 440.0 is constructed with the following multiplication it fails to serialize, var_export and json_encode properly (and probably others):

$var = "4.400000" * 100;

Test script:
---------------
$var = "4.400000" * 100;
var_export($var);
print PHP_EOL;
print json_encode($var);
print PHP_EOL;
print serialize($var);
print PHP_EOL;

// Output:
// 440.00000000000006
// 440.00000000000006
// d:440.00000000000006;

Expected result:
----------------
440.0
440
d:440;

Actual result:
--------------
440.00000000000006
440.00000000000006
d:440.00000000000006;

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-10-18 11:39 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2019-10-18 11:39 UTC] requinix@php.net
Floating point values have a limited precision. Hence a value might
not have the same string representation after any processing. That also
includes writing a floating point value in your script and directly
printing it without any mathematical operations.

If you would like to know more about "floats" and what IEEE
754 is, read this:
http://www.floating-point-gui.de/

Thank you for your interest in PHP.


 [2019-10-18 12:24 UTC] eirik at nymedia dot no
Thanks for responding! I appreciate that. However, I do find it strange that this provides different results:

var_export(440.0);
print PHP_EOL;
var_export((float) "440.0");
print PHP_EOL;
var_export("44.0" * 10);
print PHP_EOL;
var_export("0.44" * 1000);
print PHP_EOL;
var_export("4.4" * 100);
print PHP_EOL;
var_export("4.400000" * 100);
print PHP_EOL;

This prints

440.0
440.0
440.0
440.0
440.00000000000006
440.00000000000006

And speaking about string representation. I do not know the internals of php at all, but for all of the above, using other functions like print_r, var_dump and so on - even casting them to string, produces the same result for all of the floats.

And to add to this, replacing the float 440.0 with something else. Say 666.0. Produces the expected output.

Just wanted to add this to the conversation. I am not well enough versed in internals and floating points to say if the above is also expected, so feel free to keep as "Not a bug" if it fits the description well :)
 [2019-10-18 12:51 UTC] requinix@php.net
It isn't a matter of PHP's internals: this awkwardness with floating-point (non-integer) values exists in basically every programming language. Yes, you get different results with different operations and numbers. That's just how it is.

If you missed it, the answer is typically to round() your result to one or two more decimal places than you care about

  $var = round("4.400000" * 100, 3);

and/or to edit the assorted "precision" php.ini settings.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 09 11:01:28 2024 UTC