Bug #54056 [Opn->Wfx]: number_format returns an incorrect answer for certain parameters
| From: | cataphract@php.net | Date: | Mon, 21 Feb 2011 07:17:17 +0000 |
| Subject: | Bug #54056 [Opn->Wfx]: number_format returns an incorrect answer for certain parameters | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-158920@lists.php.net to get a copy of this message | ||
Edit report at http://bugs.php.net/bug.php?id=54056&edit=1
ID: 54056
Updated by: cataphract@php.net
Reported by: mr_platelet+jin6vr at fastmail dot fm
Summary: number_format returns an incorrect answer for
certain parameters
-Status: Open
+Status: Wont fix
Type: Bug
Package: Strings related
Operating System: Linux
PHP Version: 5.3.5
Block user comment: N
Private report: N
New Comment:
PHP's implementation of spprintf, used by number_format, admits (if I'm
reading the code right) a maximum of 318 digits for the 'f' mode and 319
for 'e'.
This is because PHP relies on a buffer with 500 bytes
(formatted_print.c) or 512 bytes (snprint.c and spprintf.c) to hold the
resulting conversion of the number, so a larger number of digits could
overflow the buffer.
Given this, we could increase the buffer, limit the number of digits, or
dynamically allocate the buffer. Given the near absence of interest in
such number of decimal places, the current solution of limiting the
number of digits seems appropriate.
Won't fix.
Previous Comments:
------------------------------------------------------------------------
[2011-02-20 17:19:45] mr_platelet+jin6vr at fastmail dot fm
Arbitrary precision is not needed, because
in each of the two scripts, the numbers
generated using pow can be perfectly
represented as IEEE double-precision
floating-point numbers.
I'll add an extra line of code to the first
script in order to explain better what the
problem is. Here's the new script.
-------------------
<?php
$x = pow(2, -1074);
# new line of code here:
printf("This shows that \$x is not zero:\n %.53e\n\n", $x);
$s = number_format($x, 1074, '.', '');
if(trim($s, '0') === '.') {
print "\$s represents zero, which is wrong.\n";
}
-------------------
On my system, the output of the script is:
-------------------
This shows that $x is not zero:
4.94065645841246544176568792868221372365059802614324764e-324
$s represents zero, which is wrong.
-------------------
$s definitely should not represent zero,
because 1074 (the second argument of
number_format) is exactly the number
of decimal digits needed to perfectly
represent 2 to the power of -1074.
More generally, for any positive integer
n, the number 2^-n can be perfectly
represented in base 10 using n decimal
digits, as can be seen by considering the
following sequence:
2^-1 = 0.5
2^-2 = 0.25
2^-3 = 0.125
2^-4 = 0.0625
2^-5 = 0.03125
2^-6 = 0.015625
2^-7 = 0.0078125
2^-8 = 0.00390625
2^-9 = 0.001953125
------------------------------------------------------------------------
[2011-02-20 16:37:22] rasmus@php.net
I'm not sure what you are expecting here. number_format() is not an
arbitrary
precision function. You are limited by the double precision of your
operating
system.
------------------------------------------------------------------------
[2011-02-20 14:33:45] mr_platelet+jin6vr at fastmail dot fm
The following script shows further problems with
number_format.
------------------
<?php
$count = 0;
$wrong = 0;
for($i = 319; $i <= 1074; $i++) {
$s1 = number_format(pow(2, -$i), $i, '.', '');
$s2 = bcpow(2, -$i, $i);
$s1 = trim($s1, '0');
$s2 = trim($s2, '0');
$count++;
$wrong += ($s1 !== $s2);
}
print "Number of calculations: $count\n";
print "Number of wrong answers: $wrong\n";
------------------
When I run the script, it prints:
Number of calculations: 756
Number of wrong answers: 756
Some extra information. (1) When running
each of the 2 scripts I've supplied, I
used PHP's "-n" switch. (2) Here is the
"configure" command I used when building
PHP:
--prefix=/usr/local/php/5.3.5 --disable-all --enable-bcmath
------------------------------------------------------------------------
[2011-02-20 14:17:59] mr_platelet+jin6vr at fastmail dot fm
Description:
------------
In the script below, number_format returns a string
representing zero, which is quite wrong.
Test script:
---------------
<?php
$x = pow(2, -1074);
$s = number_format($x, 1074, '.', '');
if(trim($s, '0') === '.') {
print "\$s represents zero, which is wrong.\n";
}
Expected result:
----------------
I expect to see no output.
Actual result:
--------------
The script outputs the following message:
$s represents zero, which is wrong.
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/bug.php?id=54056&edit=1