php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75800 json_encode produces unexpected results with summed floats
Submitted: 2018-01-11 11:50 UTC Modified: 2018-01-12 11:08 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: yoch at yoch dot org Assigned:
Status: Not a bug Package: JSON related
PHP Version: 7.2.1 OS: Ubuntu 16.04.3 LTS
Private report: No CVE-ID: None
 [2018-01-11 11:50 UTC] yoch at yoch dot org
Description:
------------
With default php.ini settings (serialize_precision = "-1" and precision = "14"), json_encode() produces inconsistent results.
After setting serialize_precision to "14" serialization working as expected.

Test script:
---------------
php -r 'echo 2.09 + 0.4;'
php -r 'echo json_encode(2.49);'
php -r 'echo json_encode(2.09 + 0.4);'

Expected result:
----------------
2.49
2.49
2.49

Actual result:
--------------
2.49
2.49
2.4899999999999998

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-01-11 12:27 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2018-01-11 12:27 UTC] requinix@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

http://php.net/manual/en/function.json-encode.php
> Changelog
> 7.1.0  serialize_precision is used instead of precision when encoding double values.
 [2018-01-11 12:45 UTC] yoch at yoch dot org
Does that means that setting both "precision" and "serialize_precision" to "-1" must produce the expected results? It does not right now.
 [2018-01-11 15:05 UTC] requinix@php.net
We have a template response for that one too, actually:


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/


-1 is "unlimited" precision, meaning that you can see the full float value - including possible error introduced during math. The two json_encode() tests produce different results because of the inconsis-- I mean, the magic of floating-point math.

To get the expected result in all cases you need a precision and serialize_precision of some value between 3 and 16, such as 14.

2.4899999999999998
   ^            ^
   3            16
 [2018-01-11 15:21 UTC] spam2 at rhsoft dot net
and why "precision" defaults to 14 while serialize_precision defaults to -1
 [2018-01-12 10:41 UTC] yoch at yoch dot org
Damian, thanks for the explanation.

In this case i believe "serialize_precision" should default to the "precision" value to produce predictable results out of the box.
 [2018-01-12 11:08 UTC] requinix@php.net
> In this case i believe "serialize_precision" should default to the "precision" value to produce predictable results
> out of the box.
They serve two different purposes. serialize_precision is meant to be used in situations where the complete value is needed, such as serialization (obviously). precision is more for general-purpose conversions and output where some rounding is desirable.

What changed in PHP 7.1 was that json_encode() with floats should try to be as precise as possible because it acts more like serialization than as a float-to-string conversion.
https://wiki.php.net/rfc/precise_float_value
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 30 14:01:28 2024 UTC