Это не вопрос, так как нужно знать. Я обновил приложение, использующее json_encode()
PHP7.1.1, и обнаружил проблему с изменением числа с плавающей запятой, которое иногда увеличивалось до 17 цифр. Согласно документации, PHP 7.1.x начал использовать serialize_precision
вместо точности при кодировании двойных значений. Я предполагаю, что это вызвало примерное значение
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"
}
},
ini_set('serialize_precision', 14); ini_set('precision', 14);
вероятно, заставит его сериализоваться, как раньше, однако, если вы действительно полагаетесь на определенную точность своих поплавков, вы делаете что-то не так.Ответы:
Это немного свело меня с ума, пока я наконец не нашел эту ошибку, которая указывает вам на этот RFC, в котором говорится
И (выделено мной)
Короче говоря, есть новый способ заставить PHP 7.1
json_encode
использовать новый улучшенный механизм точности. В php.ini вам нужно изменитьserialize_precision
наserialize_precision = -1
Вы можете убедиться, что он работает с этой командной строкой
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Ты должен получить
{"price":45.99}
источник
G(precision)=-1
аPG(serialize_precision)=-1
также может использоваться в PHP 5.4serialize_precision = -1
. С -1 этот кодecho json_encode([528.56 * 100]);
печатает[52855.99999999999]
json_encode
проблемаКак разработчик плагинов у меня нет общего доступа к настройкам php.ini сервера. Итак, основываясь на ответе Machavity, я написал этот небольшой фрагмент кода, который вы можете использовать в своем PHP-скрипте. Просто поместите его поверх скрипта, и json_encode продолжит работать как обычно.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
В некоторых случаях необходимо установить еще одну переменную. Я добавляю это как второе решение, потому что я не уверен, что второе решение работает нормально во всех случаях, когда первое решение оказалось эффективным.
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, это будет строка, поскольку она будет заключена в двойные кавычки.
источник
Я решил это, установив для точности и serialize_precision одно и то же значение (10):
ini_set('precision', 10); ini_set('serialize_precision', 10);
Вы также можете установить это в своем php.ini
источник
У меня была такая же проблема, но только serialize_precision = -1 не решила проблему. Мне пришлось сделать еще один шаг, чтобы обновить значение точности с 14 до 17 (как это было установлено в моем ini-файле PHP7.0). Очевидно, изменение значения этого числа изменяет значение вычисляемого числа с плавающей запятой.
источник
Другие решения не помогли мне. Вот что мне пришлось добавить в начале выполнения кода:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
источник
Что касается меня, проблема заключалась в том, что JSON_NUMERIC_CHECK в качестве второго аргумента json_encode () передавался, который приводил все типы чисел к int (не только целочисленному)
источник
Сохраните его как строку с точной точностью, которая вам нужна, используя
number_format
, а затемjson_encode
используйтеJSON_NUMERIC_CHECK
опцию:$foo = array('max' => number_format(472.185, 3, '.', '')); print_r(json_encode($foo, JSON_NUMERIC_CHECK));
Вы получаете:
{"max": 472.185}
Обратите внимание, что при этом ВСЕ числовые строки в исходном объекте будут закодированы как числа в результирующем JSON.
источник
$val1 = 5.5; $val2 = (1.055 - 1) * 100; $val3 = (float)(string) ((1.055 - 1) * 100); var_dump(json_encode(['val1' => $val1, 'val2' => $val2, 'val3' => $val3]));
{ "val1": 5.5, "val2": 5.499999999999994, "val3": 5.5 }
источник
Похоже, проблема возникает, когда
serialize
иserialize_precision
установлены разные значения. В моем случае 14 и 17 соответственно. Установка их обоих на 14 решила проблему, как и установкаserialize_precision
на -1.Значение по умолчанию
serialize_precision
было изменено на -1 в PHP 7.1.0, что означает «будет использоваться улучшенный алгоритм округления таких чисел». Но если вы все еще сталкиваетесь с этой проблемой, это может быть связано с тем, что у вас есть файл конфигурации PHP из предыдущей версии. (Может быть, вы сохранили свой файл конфигурации при обновлении?)Еще одна вещь, которую следует учитывать, - имеет ли смысл вообще использовать значения с плавающей запятой в вашем случае. Может иметь смысл или не иметь смысла использовать строковые значения, содержащие ваши числа, чтобы гарантировать, что в вашем JSON всегда сохраняется правильное количество десятичных знаков.
источник
Вы можете изменить [max] => 472.185 с числа с плавающей запятой на строку ([max] => '472.185') перед json_encode (). Поскольку json в любом случае является строкой, преобразование ваших значений с плавающей запятой в строки до того, как json_encode () сохранит желаемое значение.
источник