|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2009-01-20 14:55 UTC] exploringbinary at gmail dot com
Description:
------------
printf will not print more than 40 decimal places, even if the format specifier asks for more. For example,
<?php
$value = 0.00000000000000011102230246251565404236316680908203125; // 2^-53
printf ("%1.53f",$value); // Prints only 40 decimal places: 0.0000000000000001110223024625156540423632
?>
Contrast this with javascript:
<script type="text/javascript">
var value = 0.00000000000000011102230246251565404236316680908203125; // 2^-53
var result = value.toFixed(53);
document.write (result); // Prints all 53 decimal places
</script>
I reported a similar bug in Visual Studio, which Microsoft acknowledged as an error: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=329278
Reproduce code:
---------------
<?php
$value = 0.00000000000000011102230246251565404236316680908203125; // 2^-53
printf ("%1.53f",$value); // Prints only 40 decimal places: 0.0000000000000001110223024625156540423632
?>
Expected result:
----------------
I expect to see all 53 decimal places printed: 0.00000000000000011102230246251565404236316680908203125
Actual result:
--------------
Only 40 decimal places are printed: 0.0000000000000001110223024625156540423632
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Nov 01 01:00:01 2025 UTC |
Since I didn't find anything in the documentation, I poked around in the source code. In php-5.2.8\ext\standard\formatted_print.c I found this: #define MAX_FLOAT_PRECISION 40 There is no explanation as to why it's capped at 40. What's interesting is that this code prints only 40 decimal places (0.0000000000004547473508864641189575195312), without a warning: <?php /* Print 2^-41 */ $dyadic = 0.00000000000045474735088646411895751953125; printf ("%1.2147483646f",$dyadic); ?> While this code prints ``Warning: printf() [function.printf]: Precision must be greater than zero and less than 2147483647 ...'' <?php /* Print 2^-41 */ $dyadic = 0.00000000000045474735088646411895751953125; printf ("%1.2147483647f",$dyadic); ?> If you're going to warn about a maximum, why not warn about the real maximum -- 40, not 2147483646? I wrote an article about how this issue is handled in PHP and 7 other languages at http://www.exploringbinary.com/print-precision-of-dyadic-fractions-varies-by-language/A reader of my blog pointed out that serialize and unserialize have similar issues. I ran some tests and discovered that 2^-143 is the smallest negative power of two that PHP can serialize, and 2^-40 is the smallest it can unserialize. Here's are the testcases: This code works ? it prints d:8.9683101716788292539118693330554632401936764280097009392452370 16894662929189507849514484405517578125E-44; <?php //Serialize 2^-143 $dyadic = //Compute as (2^-50)^2 * 2^-43 to break up 0.00000000000000088817841970012523233890533447265625* 0.00000000000000088817841970012523233890533447265625* 0.0000000000001136868377216160297393798828125; echo serialize ($dyadic); ?> This code fails ? it prints d:4.4841550858394146269559346665277316200968382140048504696226185 08447331464594753924757242202758789062E-44; <?php //Serialize 2^-144 $dyadic = //Compute as (2^-50)^2 * 2^-44 to break up 0.00000000000000088817841970012523233890533447265625* 0.00000000000000088817841970012523233890533447265625* 0.00000000000005684341886080801486968994140625; echo serialize ($dyadic); ?> This code works ? it prints 0.0000000000009094947017729282379150390625 <?php //Serialize and unserialize 2^-40 $dyadic = 0.0000000000009094947017729282379150390625; printf ("%1.40f",unserialize(serialize($dyadic))); ?> This code fails ? it prints Fails, prints 0.0000000000004547473508864641189575195312 <?php //Serialize and unserialize 2^-41 $dyadic = 0.00000000000045474735088646411895751953125; printf ("%1.41f",unserialize(serialize($dyadic))); ?>