14

PHP seems to have a bug in the way it handles decimal precision in json_encode.

It's easy to see just by encoding a simple float:

echo json_encode(["testVal" => 0.830]);

// Prints out:
{"testVal":0.82999999999999996003197111349436454474925994873046875}

I'm not much of a server admin, so aside from going into the php.ini and changing serialize_precision to -1, is there anything I can do in my code to protect against this when I can't be sure it's running in an environment where that setting has been changed?

EDIT: I'm sure some comments will want to link against general discussions of why floating point imprecision exists. I know that. My question here is specifically about the best practice for dealing with it in PHP, and whether there is a way to code defensively against it. Surely there is a better way than sending floats as strings.

4
  • Does this happen in 7.0 as well? Commented May 9, 2017 at 9:22
  • As the discussion on the bug report you linked to makes clear, this is not a bug but a deliberate feature. If your server is configured to serialize floating point numbers with high precision, json_encode will now respect this. Commented May 9, 2017 at 9:22
  • And if you write that value as string? Then you have exact that number you want. Commented May 9, 2017 at 9:24
  • 0.830 cannot be represented exactly as floating point. It is an approximation. PHP provides a better approximation (with a lot of decimal places). That's all. You can format the value as string using number_format() and put the string in JSON. Or, better, you can let it be a floating point number and do the formatting just before you want to put the value on screen. Commented May 9, 2017 at 9:30

1 Answer 1

13

You should configure 'precision' and 'serialize_precision' params.

precision = 14
serialize_precision = -1

Test case:

php -r 'ini_set("precision", 14); ini_set("serialize_precision", -1); var_dump(json_encode(["testVal" => 0.830]));'
string(16) "{"testVal":0.83}"
Sign up to request clarification or add additional context in comments.

5 Comments

It might be helpful to link to the documentation changelog, where it is documented what changed. In particular, changing the precision no longer has an effect on json_encode.
@Justastudent Thanks, thats true for 7.1, many guys still use 5.6 so answer above will be useful for everybody who use 5.6+.
Yeah, I mentioned this in my original question. Is this the best solution, and if so, why? Are there any alternatives?
@GoldenJoe I think serialize_precision = -1 is more convenient than using number_format across the code. It's possible to create .user.ini in site public dir and then add serialize_precision = -1 option to it.
Although not without its limits, a simple fix is to cast the value as a string. See my answer: stackoverflow.com/a/50944401/2338825

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.