rfc:precise_float_value

Differences

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

Link to this comparison view

rfc:precise_float_value [2016/05/30 16:27]
bukka Update RFC and add me as an co-author
rfc:precise_float_value [2017/09/22 13:28]
Line 1: Line 1:
- 
-====== PHP RFC: More precise float value handling ====== 
-  * Version: 1.0 
-  * Date: 2015-07-30 
-  * Author: Yasuo Ohgaki <yohgaki@ohgaki.net>, Jakub Zelenka <bukka@php.net> 
-  * Status: Under Discussion 
-  * First Published at: http://wiki.php.net/rfc/precise_float_value 
- 
-===== Introduction ===== 
- 
-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 handled as precise as possible by default.  
- 
-Currently, json_encode() uses EG(precision) which is set to 14. That means that 14 digits max are used for displaying (printing) the number. IEEE 754 double supports higher precision and serialize()/var_export() uses PG(serialize_precision)=17 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> 
-<?php 
-$j = '{ "v": 0.1234567890123456789 }'; 
-var_dump(json_decode($j)); 
-var_dump(json_encode(json_decode($j))); 
-ini_set('precision', 20); 
-var_dump(json_decode($j)); 
-var_dump(json_encode(json_decode($j))); 
-var_dump(0.1234567890123456789); 
-?> 
-</code> 
- 
-<code> 
-object(stdClass)#1 (1) { 
-  ["v"]=> 
-  float(0.12345678901235) 
-} 
-string(22) "{"v":0.12345678901235}" 
-object(stdClass)#1 (1) { 
-  ["v"]=> 
-  float(0.12345678901234567737) 
-} 
-string(28) "{"v":0.12345678901234567737}" 
-float(0.12345678901234567737) 
-</code> 
- 
-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 EG(precision)/PG(serialize_precision). 
- 
-<code php> 
-<?php 
-$v = 0.12345678901234567890; 
-var_dump($v); 
-ini_set('precision', 100); 
-var_dump($v); 
-?> 
-</code> 
- 
-<code> 
-float(0.12345678901235) 
-float(0.12345678901234567736988623209981597028672695159912109375) 
-</code> 
- 
-That is caused by used mode for double to string conversion. 
- 
-===== Proposal ===== 
- 
-This RFC proposes to introduce EG(precision)=-1 and PG(serialize_precision)=-1 that uses zend_dtoa()'s mode 0 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. It means to add JSON_G(json.precision) which will be used for JSON module specific precision INI setting. 
- 
-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); 
-ini_set('json.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); 
-ini_set('json.precision', 14); 
- 
-var_dump($v); 
-echo var_export($v, true), PHP_EOL; 
-echo json_encode($v), PHP_EOL; 
-echo $v, PHP_EOL; 
-?> 
-</code> 
- 
-  float(10) 
-  10.000000000000011 
-  10 
-  10 
- 
- 
-Please note that IEEE float cannot store exactly precise values. e.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 ===== 
- 
-Setting mode 0 as default can mean that the rounding will be more precise which also means that the rounding might be different in var_export()/serialize(). 
- 
-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 even when 0 mode is used. 
- 
-None when old INI value is used. 
- 
-===== Proposed PHP Version(s) ===== 
- 
-  * PHP 7.1 
- 
-===== RFC Impact ===== 
-==== To SAPIs ==== 
-None. 
- 
-==== To Existing Extensions ==== 
-PHP overall 
-  * 0 mode (EG(precision)= -1) float outputs values rounded to nearest. 
- 
-Standard module 
-  * serialize(), var_export() - Use PG(serialize_precision) and 0 mode by default. 
- 
-JSON 
-  * json_encode() - Use ini selected from the vote result and 0 mode by default. 
- 
- 
-==== To Opcache ==== 
- 
-Not affected. 
- 
-==== New Constants ==== 
- 
-None. 
- 
-==== php.ini Defaults ==== 
- 
-precision 
-  * hardcoded default values : 14 Unmodified 
-  * php.ini-development values : 14 Unmodified 
-  * php.ini-production values : 14 Unmodified 
- 
-serialize_precision 
-  * hardcoded default values : -1 
-  * php.ini-development values : -1 
-  * php.ini-production values : -1 
- 
-json.precision (if accepted) 
-  * hardcoded default values : -1 
-  * php.ini-development values : -1 
-  * php.ini-production values : -1 
- 
- 
-===== Open Issues ===== 
- 
-None. 
- 
-===== Unaffected PHP Functionality ===== 
- 
-PHP uses "raw" IEEE 754 value internally regardless of precision settings. Therefore, this RFC does not affect internal computation. 
- 
- 
-===== Future Scope ===== 
- 
-WDDX 
-  * wddx_serialize_vars/value() - Use PG(serialize_precision) and 0 mode. It uses EG(precision) currently. 
- 
-XML_RPC 
-  * xmlrpc_encode() - Use PG(serialize_precision) and 0 mode. It uses EG(precision) currently. 
- 
- 
-===== Proposed Voting Choices ===== 
- 
-Requires a 50%+1 majority 
- 
-There will be two votings 
- 
-  * whether to introduce mode 0 as default 
-  * what precision ini should be used for json (precision, serialize_precision, json.precision). 
- 
-===== Patches and Tests ===== 
- 
-  * https://github.com/php/php-src/pull/1455 
- 
-===== Implementation ===== 
-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 
- 
-===== References ===== 
- 
-  * 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 ===== 
-Keep this updated with features that were discussed on the mail lists. 
  
rfc/precise_float_value.txt · Last modified: 2017/09/22 13:28 (external edit)