Why does PHP's sprintf not round 5s reliably?

后端 未结 3 723
梦如初夏
梦如初夏 2020-12-11 14:25

I was relying on sprintf(\'%0.1f\', 2.25) === \'2.3\' but it turns out it comes in at 2.2!

In fact it seems random:

php >         


        
相关标签:
3条回答
  • 2020-12-11 14:48

    You should be using round

    http://php.net/manual/en/function.round.php

    round(2.25, 2) === floatval('2.3')
    
    0 讨论(0)
  • 2020-12-11 14:57

    As an explanation of why round can offer better results than a function not specifically designed for rounding, we need to consider the limits of the double precision floating point representation. Doubles can represent between 15 and 17 decimal significand digits. From the Wikipedia article on double precision:

    If a decimal string with at most 15 significant digits is converted to IEEE 754 double precision representation and then converted back to a string with the same number of significant digits, then the final string should match the original. If an IEEE 754 double precision is converted to a decimal string with at least 17 significant digits and then converted back to double, then the final number must match the original

    The implementation of round can and should make use of this to "do the right thing" in most cases.

    Example 1:

    <?=number_format(2.05,14); //give me 15 significant digits. Guaranteed to produce the orginal number
    

    outputs:

    2.05000000000000
    

    Example 2:

    <?=number_format(2.05,16); //give me 17 significant digits. Not guaranteed to produce the orginal number
    

    outputs:

    2.0499999999999998
    

    This is just a demonstration the IEEE 754 behavior.

    I am going to guess (because I haven't read its implementation) that sprintf doesn't really try to do anything particularly intelligent with regards to rounding, whereas round probably tries to round "correctly" (per IEEE 754) with respect to the number of significant digits you asked for.

    0 讨论(0)
  • 2020-12-11 15:08

    To summarise what has been said in comments in an answer:

    Because printf is not a rounding function, but a low-level function to give a string representation of a number. In this case the number internally is not the same as the number set, e.g. it might be 2.249999991231231123 because of the limitations of the floating point internal representation.

    So printf is rounding a different number to that which you entered/calculated, which is correctly 2.2 in this example.

    Therefore as the other answer (and my original question) points out, a better solution is to use round() (and possibly sprintf upon the result).

    0 讨论(0)
提交回复
热议问题