rfc:precise_float_value

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rfc:precise_float_value [2015/08/05 07:38]
yohgaki
rfc:precise_float_value [2017/09/22 13:28] (current)
Line 1: Line 1:
 ====== PHP RFC: More precise float value handling ====== ====== PHP RFC: More precise float value handling ======
-  * Version: 0.9+  * Version: 1.1
   * Date: 2015-07-30   * Date: 2015-07-30
-  * Author: Yasuo Ohgaki <yohgaki@ohgaki.net> +  * Author: Yasuo Ohgaki <yohgaki@ohgaki.net>, Jakub Zelenka <bukka@php.net> 
-  * Status: Under Discussion+  * Status: Implemented (PHP 7.1)
   * First Published at: http://wiki.php.net/rfc/precise_float_value   * First Published at: http://wiki.php.net/rfc/precise_float_value
  
 ===== Introduction ===== ===== Introduction =====
  
-This RFC is based on float like JSON numeric discussion and proposes more precise float value handling overall.+This RFC is based on the discussion about displaying float values in json_encode and proposes more precise float value handling overall.
  
-JSON is used to exchange data between systems. Although [[https://tools.ietf.org/html/rfc7159|JSON RFC "6 Numbers"]]  does not require specific implementation for float/int type, float value should be able to handle precise float values as much as possible by default. +JSON is used to exchange data between systems. Although [[https://tools.ietf.org/html/rfc7159|JSON RFC "6 Numbers"]] does not require specific implementation for float/int type, float value should be handled as precise as possible by default.
  
-Currentlyjson_encode() uses PG(precision) which is 14. IEEE 754 double supports more precision and serialize()/var_export() uses PG(serialize_precision)=17 to be more precise. Since json_encode() uses PG(precision), json_encode() removes lower digits of fraction parts and destroys original value even if PHP's float could hold more precise float value. +Currently json_encode() uses EG(precision) which is set to 14. That means that 14 digits at most are used for displaying (printing) the number. IEEE 754 double supports higher precision and serialize()/var_export() uses PG(serialize_precision) which set to 17 be default to be more precise. Since json_encode() uses EG(precision), json_encode() removes lower digits of fraction parts and destroys original value even if PHP's float could hold more precise float value.
  
 <code php> <code php>
Line 40: Line 40:
 </code> </code>
  
-PHP's float type stores "raw" IEEE 754 double and could store accurate fraction value up 17 digits.+PHP's float type stores "raw" IEEE 754 double and could display accurate fraction value up to 17 digits.
  
-Current PHP outputs meaningless values for oversized PG(precision)/PG(serialize_precision).+Current PHP outputs meaningless values for oversized EG(precision)/PG(serialize_precision).
  
 <code php> <code php>
Line 57: Line 57:
 float(0.12345678901234567736988623209981597028672695159912109375) float(0.12345678901234567736988623209981597028672695159912109375)
 </code> </code>
 +
 +That is caused by used mode for double to string conversion.
  
 ===== Proposal ===== ===== Proposal =====
  
-  * PHP 7.0: Introduce PG(precision)=-1 and PG(serialize_precision)=-1 that uses zend_dtoa()'s 0 mode that rounds to nearest value. (-1 is used to indicate 0 mode)+This RFC proposes to introduce a new setting EG(precision)=-1 and PG(serialize_precision)=-1 that uses zend_dtoa()'mode which uses better algorigthm for rounding float numbers (-1 is used to indicate 0 mode).
  
-Since JSON is used extensively for web apps, we may have JSON specific INI setting for better compatibility and ease of use.+The RFC also proposes changing ini for JSON precision to PG(serialize_precision). 
 + 
 +Followings are sample codes and outputs of the proposed patch. 
 + 
 +NEW behavior 
 +<code php> 
 +<?php 
 +$v = 10.0000000000001; 
 + 
 +ini_set('precision', -1); 
 +ini_set('serialize_precision', -1); 
 + 
 +var_dump($v); 
 +echo var_export($v, true), PHP_EOL; 
 +echo json_encode($v), PHP_EOL; 
 +echo $v, PHP_EOL; 
 +?> 
 +</code> 
 + 
 +  float(10.0000000000001) 
 +  10.0000000000001 
 +  10.0000000000001 
 +  10.0000000000001 
 + 
 + 
 + 
 +OLD behavior 
 +<code php> 
 +<?php 
 +$v = 10.00000000000001; 
 + 
 +ini_set('precision', 14); 
 +ini_set('serialize_precision', 17); 
 + 
 +var_dump($v); 
 +echo var_export($v, true), PHP_EOL; 
 +ini_set('serialize_precision', 14); 
 +echo json_encode($v), PHP_EOL; 
 +ini_set('serialize_precision', 17); 
 +echo $v, PHP_EOL; 
 +?> 
 +</code>
  
-  * PHP 7.0: Add JSON_G(json_precision- Add JSON module specific precision INI setting.+  float(10) 
 +  10.000000000000011 
 +  10 
 +  10
  
-PHP 5.6's json_encode() uses PG(precision) and could lose floating point number information.  
  
-  * PHP 5.6: Make json_encode() uses PG(serialize_precision).+Please note that IEEE float cannot store exactly precise valuese.g. Result of "10/3" - see phpt of the patch. Even with this proposal, there will be rounding errors, but the behavior becomes similar to other languages and values are more precise in many cases.
  
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
  
-PHP 7.0 will have 0 mode as the defaultvar_export()/serialize() may have different number+Setting mode as default can mean that the rounding will be more precise which also means that the rounding might be different in var_export()/serialize().
  
-FYI: Existing tests passes even when 0 mode is used.+The BC break could happen only if someone would rely on exact output but that shouldn't be the case. All our existing tests passes when 0 mode is used.
  
 None when old INI value is used. None when old INI value is used.
Line 81: Line 126:
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
  
-PHP 7.0.0 - PG(serialize)/PG(serialize_precision) 0 mode and JSON_G(json_precision) +  * PHP 7.1
-PHP 5.6.x - JSON uses PG(serialize_precision) for float precision.+
  
 ===== RFC Impact ===== ===== RFC Impact =====
Line 90: Line 134:
 ==== To Existing Extensions ==== ==== To Existing Extensions ====
 PHP overall PHP overall
-  * 0 mode (PG(precision)= -1) float outputs values rounded to nearest.+  * 0 mode (EG(precision)= -1) float outputs values rounded to nearest.
  
-Standard module +Standard module and JSON 
-  * serialize(), var_export() - PHP7.0: Use PG(serialieze_precision) and 0 mode. +  * serialize(), var_export()json_encode - Use PG(serialize_precision) and 0 mode by default.
- +
-JSON +
-  * json_encode() PHP7.0: Use PG(serialize_precision) and 0 mode. PHP5.6: Use PG(serialize_precision).  It uses PG(precision) currently. +
- +
-WDDX +
-  * wddx_serialize_vars/value() - PHP7.0: Use PG(serialize_precision) and 0 mode. It uses PG(precision) currently. +
- +
-XML_RPC +
-  * xmlrpc_encode() - PHP7.0: Use PG(serialize_precision) and 0 mode. It uses PG(precision) currently.+
  
 ==== To Opcache ==== ==== To Opcache ====
Line 119: Line 154:
   * php.ini-production values : 14 Unmodified   * php.ini-production values : 14 Unmodified
  
-serialize_precision(PHP5.6) +serialize_precision
-  * hardcoded default values : 17 Unmodified +
-  * php.ini-development values : 17 Unmodified +
-  * php.ini-production values : 17 Unmodified +
- +
-serialize_precision(PHP7) +
-  * hardcoded default values : -1 +
-  * php.ini-development values : -1 +
-  * php.ini-production values : -1 +
- +
-json_precision(NEW - PHP7 only)+
   * hardcoded default values : -1   * hardcoded default values : -1
   * php.ini-development values : -1   * php.ini-development values : -1
Line 146: Line 171:
 ===== Future Scope ===== ===== Future Scope =====
  
-  Remove PG(serialize_precisionsetting. If we are going to remove PG(serialize_precision) in the future, we may be better to have JSON_G(json_precisionas one may need specific precision for JSON data.+WDDX 
 +  wddx_serialize_vars/value() - Use PG(serialize_precision) and 0 mode. It uses EG(precisioncurrently.
  
-===== Proposed Voting Choices =====+XML_RPC 
 +  * xmlrpc_encode() - Use PG(serialize_precision) and 0 mode. It uses EG(precision) currently.
  
-Requires a 50%+1 majority (see [[voting]]) 
  
-<doodle title="Introduce 0 mode to PG(precision)/PG(serialize_precision) for PHP 7.0" auth="yohgaki" voteType="single" closed="True"> +===== Voting =====
-   * Yes +
-   * No +
-</doodle>+
  
-.+Requires a 2/3 majority for the first vote (mode 0 to become default for serialize precision) and 50%+1 majority for the second vote (changing default for json).
  
-<doodle title="Add JSON_G(json_precisionfor JSON module only setting for PHP 7.0" auth="yohgaki" voteType="single" closed="True">+The both votes are straight Yes/No votes. 
 + 
 +<doodle title="Should mode 0 be introduced and set as default for PG(serialize_precision)" auth="bukka" voteType="single" closed="true">
    * Yes    * Yes
    * No    * No
 </doodle> </doodle>
  
-+<doodle title="Should PG(serialize_precision) be used instead of EG(precision) in json_encode" auth="bukka" voteType="single" closed="true">
- +
-<doodle title="Make json_encode() uses PG(serialize_precision)" auth="yohgaki" voteType="single" closed="True">+
    * Yes    * Yes
    * No    * No
 </doodle> </doodle>
  
 +The votes started on 2016-06-12 at 19:00 UTC and ended on 2016-06-19 at 19:00 UTC.
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
 +
 +The initial PR can be found here:
  
   * https://github.com/php/php-src/pull/1455   * https://github.com/php/php-src/pull/1455
 +
 +Note that the PR is currently outdated but it will be updated if the RFC is accepted.
  
 ===== Implementation ===== ===== Implementation =====
 +
 +Merged into php-src for PHP 7.1: https://github.com/php/php-src/commit/75b86a2
 +
 After the project is implemented, this section should contain  After the project is implemented, this section should contain 
-  - the version(s) it was merged to 
-  - a link to the git commit(s) 
   - a link to the PHP manual entry for the feature   - a link to the PHP manual entry for the feature
  
 ===== References ===== ===== References =====
  
-https://marc.info/?l=php-internals&m=143786181229714&w=2+  * https://marc.info/?l=php-internals&m=143786181229714&w=2 
 +  * https://bugs.php.net/bug.php?id=71473 
 +  * http://blog.reverberate.org/2016/02/06/floating-point-demystified-part2.html
  
 ===== Rejected Features ===== ===== Rejected Features =====
-Keep this updated with features that were discussed on the mail lists.+ 
 +None 
rfc/precise_float_value.1438760316.txt.gz · Last modified: 2017/09/22 13:28 (external edit)