Edit report at http://bugs.php.net/bug.php?id=54056&edit=1
ID: 54056 Updated by: cataphr...@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] ras...@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