php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68200 json_decode rounding floats to 3 digits precision
Submitted: 2014-10-09 14:00 UTC Modified: 2014-10-10 18:43 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:2 (100.0%)
From: vwirus at o2 dot pl Assigned:
Status: Not a bug Package: JSON related
PHP Version: 5.5.17 OS: linux/debian
Private report: No CVE-ID: None
 [2014-10-09 14:00 UTC] vwirus at o2 dot pl
Description:
------------
json_decode rounding floats to 3 digits precision. My precision setting in php.ini shows 14.


Test script:
---------------
$tmp = json_decode('{"number":1000000.66599998}', true);
        if (false !== strpos((string) $tmp['number'], '1000000.666')) {
            echo PHP_EOL, 'WRONG', PHP_EOL;
        }
        else {
            echo PHP_EOL, 'OK', PHP_EOL;
        }
        var_dump($tmp, $tmp['number']);

Expected result:
----------------
After decode the value of $tmp['number'] should be 1000000.66599998.

Actual result:
--------------
After decode the value of $tmp['number'] shows be 1000000.666 (it rounds real value with 3 digits precision)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-10-09 14:22 UTC] marcin at urzenia dot net
It's float problem, not JSON:

var_dump((float)"1000000.66599998") => float(1000000.666)
 [2014-10-09 17:36 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2014-10-09 17:36 UTC] requinix@php.net
14 digits of precision goes all the way to
  1000000.66599998
                ^
so yes, it will round to .666. By the way, "significant digits" are not just the decimal places so it rounded to 10 digits, not 3.

Push your precision up to 15 or more and it will save as you want.
 [2014-10-10 09:20 UTC] vwirus at o2 dot pl
Thank you that solved my problem. But it's not very stright forward and not possible in  shared hosting. A s json is "transport" layer for most php apps I think there should be flag in json_decode similar to JSON_BIGINT_AS_STRING f.e. JSON_FLOAT_AS_STRING that converts floats to stings and avoid rounding and losing precision. Such string could be easy used with BC_MATH
 [2014-10-10 18:43 UTC] requinix@php.net
> But it's not very stright forward and not possible in  shared hosting.
All you need to add is
  ini_set("precision", 15);
 [2014-10-13 10:26 UTC] vwirus at o2 dot pl
You not always able to call ini_set, and i high load apps you shouldn't.
Also let's say you dealing with numbers up to 18 significant digits.
So you're setting:
ini_set('precision', 18);

but:

$tmp = json_decode('{"number": 1000000.66599998}', true);
var_dump($tmp);

displays:
array(1) {
  ["number"]=>
  float(1000000.66599997994)
}

So important information is lost!
 [2014-11-07 09:09 UTC] admin at bittylicious dot com
I absolutely second vwirus's suggestion that we add a new options flag for json_decode to also treat floats as strings.

My workaround for now, which is definitely a kludge, is to preg_replace all numbers, including floats, with quotes. This keeps things as a string and thus doesn't lose any precision.

Perhaps this can be converted to a feature request?
 [2014-11-19 22:23 UTC] admin at bittylicious dot com
I've created a feature request for this to have an option for json_decode to handle all numbers as strings. If you're never going to use the result as a double internally, this can be useful.

https://bugs.php.net/bug.php?id=68456
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 11:01:30 2024 UTC