PHP7.1 JSON encode() Float Issue
это не вопрос, это больше знать. Я обновил приложение, которое использует json_encode()
к PHP7.1.1 и я видел проблему с поплавками, которые изменяются, чтобы иногда расширять 17 цифр. Согласно документации, PHP 7.1.х начал использовать serialize_precision
вместо точности при кодировании значений Double. Я предполагаю, что это вызвало пример значения
472.185
стать
472.18500000000006
после того, как это значение прошло json_encode()
. С момента моего открытия я вернулся к PHP 7.0.16, и у меня больше нет проблемы с json_encode()
. Я также попытался обновить до PHP 7.1.2 перед возвращением обратно к PHP 7.0.16.
обоснование этого вопроса исходит из PHP-точность плавающего числа, однако конец все причины для этого из-за изменения от точности к использованию serialize_precision в json_encode()
.
если кто-нибудь знает решение этой проблемы, я был бы более чем счастлив, чтобы слушать рассуждения/исправить.
отрывок из многомерного массива (до):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
и после json_encode()
...
"staticYaxisInfo":
{
"17":
{
"variable_id": "17",
"static": "1",
"min": 0,
"max": 472.18500000000006,
"locked_static": "1"
}
},
5 ответов
это немного сводило меня с ума, пока я наконец не нашел эта ошибка что указывает на это RFC, который сказал
в настоящее время
json_encode()
использует, например (точность), которая установлена на 14. Это означает, что для отображения (печати) номера используется не более 14 цифр. IEEE 754 double поддерживает более высокую точность иserialize()
/var_export()
использует PG (serialize_precision), который установлен в 17 по умолчанию, чтобы быть более точным. Сjson_encode()
использует например (точность),json_encode()
удаляет нижние цифры частей фракции и уничтожает исходное значение, даже если float PHP может содержать более точное значение float.
и (выделено мной)
этот RFC предлагает ввести новую настройку, например (точность)=-1 и ПГ(serialize_precision)=-1, что использует zend_dtoa()'ы режим 0, который использует лучше algorigthm для округления числа с плавающей точкой (-1 используется, чтобы указать 0 режим).
короче говоря, есть новый способ сделать PHP 7.1 json_encode
используйте новый и улучшенный двигатель точности. В php.ini вам нужно изменить serialize_precision
to
serialize_precision = -1
вы можете проверить, что он работает с этой командной строкой
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
вы должны
{"price":45.99}
как разработчик плагинов у меня нет общего доступа к php.ini настройки сервера. Итак, основываясь на ответе Machavity, я написал этот небольшой фрагмент кода, который вы можете использовать в своем PHP-скрипте. Просто положите его поверх скрипта, и json_encode будет работать как обычно.
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'serialize_precision', -1 );
}
У меня была та же проблема, но только serialize_precision = -1 не решил проблему. Мне пришлось сделать еще один шаг, чтобы обновить значение точности с 14 до 17 (как это было установлено на моем PHP7.0 ini файл). По-видимому, изменение значения этого числа изменяет значение вычисляемого поплавка.
другие решения не сработали для меня. Вот что мне пришлось добавить в начале выполнения кода:
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'precision', 17 );
ini_set( 'serialize_precision', -1 );
}
Я кодировал денежные значения и имел такие вещи, как 330.46
кодирование 330.4600000000000363797880709171295166015625
. Если вы не хотите или не можете изменить настройки PHP, и вы заранее знаете структуру данных, есть очень простое решение, которое сработало для меня. Просто приведите его к строке (оба следующих делают то же самое):
$data['discount'] = (string) $data['discount'];
$data['discount'] = '' . $data['discount'];
для моего случая использования это было быстрое и эффективное решение. Просто обратите внимание, что это означает, что когда вы декодируете его из JSON, это будет строка, так как она будет завернутый в двойные кавычки.