Bug #74221 [Com]: Float precision is altered when encoding to JSON for floats 0.99... and under

From: Date: Tue, 07 Mar 2017 23:12:46 +0000
Subject: Bug #74221 [Com]: 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-207733@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 Comment by: bryn at imgur dot com 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: @nikic regardless of serialize precision, the encoded JSON value should represent the original value. The 5.x branch gets the expected result from my example. The 7.x branch does not. Also, desired precision might be different for two keys in the same JSON object. Having to juggle a global ini setting is not a very good solution. Previous Comments: ------------------------------------------------------------------------ [2017-03-07 23:06:13] nikic@php.net 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. ------------------------------------------------------------------------ [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

« previous php.bugs (#207733) next »