Bug #74221 [Opn]: Float precision is altered when encoding to JSON for floats 0.99... and under
| From: | nikic@php.net | Date: | Tue, 07 Mar 2017 23:06:15 +0000 |
| Subject: | Bug #74221 [Opn]: Float precision is altered when encoding to JSON for floats 0.99... and under | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-207732@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=74221&edit=1
ID: 74221
Updated by: nikic@php.net
Reported by: bryn at imgur dot com
Summary: Float precision is altered when encoding to JSON for
floats 0.99... and under
Status: Open
Type: Bug
Package: JSON related
Operating System: Ubuntu 16.04.2 LTS
PHP Version: 7.1.2
Block user comment: N
Private report: N
New Comment:
You can restore the previous behavior by setting serialize_precision to the value of precision,
which is 14 by default. Alternatively and preferably, you can set serialize_precision to -1. In this
case PHP will automatically determine the minimal precision necessary to still accurately represent
the number.
Previous Comments:
------------------------------------------------------------------------
[2017-03-07 22:49:10] bryn at imgur dot com
Description:
------------
The change to using
serialize_precision in json_encode() may have had some
side affects. Floating point numbers under 1.0 get a different precision than other floating point
numbers and the precision for those numbers can be unpredictable.
I noticed that var_export() is behaving the in the same way, but that is far less
critical because it's not used as a data exchange format.
At the moment, I have a single workaround for a single case - When encoding a JSON object only
dealing with the exact same precision values, setting serialize_precision to 2 gives
the expected result. That won't work for objects with mixed precision though.
Test script:
---------------
<?php
# Getting the precision on the cli seems to change it.
# Before these two lines were added, I was getting 53 points of precision.
# After, it adhered to the value for serialize_precision and stayed there.
#print 'Precision is set to '.ini_get('precision').PHP_EOL;
#print 'Serialize Precision is set to '.ini_get('serialize_precision').PHP_EOL;
$data = array(
0.35,
(float)0.35,
round(0.35, 2),
0.15,
1.25,
1.23,
1.0,
0.9,
4,
);
print 'var_export: '.PHP_EOL.var_export($data, 1).PHP_EOL;
print 'json_encode: '.PHP_EOL.json_encode($data, JSON_PRESERVE_ZERO_FRACTION).PHP_EOL;
print 'print_r'.PHP_EOL;
print_r($data);
Expected result:
----------------
var_export:
array (
0 => 0.35,
1 => 0.35,
2 => 0.35,
3 => 0.15,
4 => 1.25,
5 => 1.23,
6 => 1.0,
7 => 0.9,
8 => 4,
)
json_encode:
[0.35,0.35,0.35,0.15,1.25,1.23,1.0,0.9,4]
print_r
Array
(
[0] => 0.35
[1] => 0.35
[2] => 0.35
[3] => 0.15
[4] => 1.25
[5] => 1.23
[6] => 1
[7] => 0.9
[8] => 4
)
Actual result:
--------------
var_export:
array (
0 => 0.34999999999999997779553950749686919152736663818359375,
1 => 0.34999999999999997779553950749686919152736663818359375,
2 => 0.34999999999999997779553950749686919152736663818359375,
3 => 0.1499999999999999944488848768742172978818416595458984375,
4 => 1.25,
5 => 1.229999999999999982236431605997495353221893310546875,
6 => 1.0,
7 => 0.90000000000000002220446049250313080847263336181640625,
8 => 4,
)
json_encode:
[0.34999999999999997779553950749686919152736663818359375,0.34999999999999997779553950749686919152736663818359375,0.34999999999999997779553950749686919152736663818359375,0.1499999999999999944488848768742172978818416595458984375,1.25,1.229999999999999982236431605997495353221893310546875,1.0,0.90000000000000002220446049250313080847263336181640625,4]
print_r
Array
(
[0] => 0.35
[1] => 0.35
[2] => 0.35
[3] => 0.15
[4] => 1.25
[5] => 1.23
[6] => 1
[7] => 0.9
[8] => 4
)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=74221&edit=1