2

Recently came across a situation where I was working on a server that had a php.ini file with:

precision = 16

The default being 14, this seems harmless enough. Unfortunately it lead to this:

// ini_set('precision', 16);
echo round((20.12 / 36.79),4);

Result: 0.5469000000000001

Huh? Shouldn't round() be taking care of the floating point precision issues here?

  • err, what..? can mention the php version? – Bagus Tesa Apr 25 '17 at 01:06
  • Doesn't seem to matter as it's a float precision issue. Tested and same result php 5.3 - php 7.0 – But those new buttons though.. Apr 25 '17 at 01:07
  • 1
    ah i see, looks like we missed the concept of truncating vs rounding.. well [some discussion on floating points](http://stackoverflow.com/a/14656315/4648586) – Bagus Tesa Apr 25 '17 at 01:12
  • I'm familiar with the concept - I just (wrongly) assumed that `round()` would take care of business here. I guess as long as it's returning a float it will be prone to this kind of behavior. – But those new buttons though.. Apr 25 '17 at 01:19
  • [`round()`](http://php.net/manual/en/function.round.php) returns a float, and that float still has a margin of error if you turn up the display precision high enough to see it. If you want to format a number for display then you need to use something like [`sprintf()`](http://php.net/manual/en/function.sprintf.php) or [`number_format()`](http://php.net/manual/en/function.number-format.php). Also, if you're dealing with money you need to not use floats *at all*. – Sammitch Apr 25 '17 at 01:41
  • @Sammitch - That makes sense, however neither of those functions actually round - in the end I'm first rounding, then truncating which gives the desired result. – But those new buttons though.. Apr 25 '17 at 02:31
  • it may help someone reading these comments to know that `number_format()` takes care of rounding and returns a string so is not subject to float issues. I wrongly assumed that `number_format()` only truncates but it actually rounds properly as well. e.g., `number_format(1.237,2) == "1.24"` – But those new buttons though.. Feb 09 '18 at 16:51

1 Answers1

1

php's round() function still returns a floating point number, not a string, so it might be inexact.

0.5469 is presented as the following 8 bytes 0x3FE180346DC5D639 encoded double precision IEEE754.

Which is not the exact representation of 0.5469 but a closest representible number, which actually is 5.46900000000000052757798130187E-1

References:

zerkms
  • 249,484
  • 69
  • 436
  • 539