Esta no es una pregunta, ya que es más un aviso. json_encode()
Actualicé una aplicación que usa PHP7.1.1 y estaba viendo un problema con los flotadores que se cambiaban para extenderse a veces hasta 17 dígitos. Según la documentación, PHP 7.1.x comenzó a usarse en serialize_precision
lugar de precisión al codificar valores dobles. Supongo que esto provocó un valor de ejemplo de
472.185
convertirse
472.18500000000006
después de que ese valor pasó json_encode()
. Desde mi descubrimiento, he vuelto a PHP 7.0.16 y ya no tengo el problema con json_encode()
. También intenté actualizar a PHP 7.1.2 antes de volver a PHP 7.0.16.
El razonamiento detrás de esta pregunta proviene de PHP - Precisión de números flotantes , sin embargo, la razón final de esto se debe al cambio de precisión al uso de serialize_precision en json_encode()
.
Si alguien sabe de una solución a este problema, estaría más que feliz de escuchar el razonamiento / solución.
Extracto de una matriz multidimensional (antes):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
y después de pasar por 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);
probablemente haría que se serializara como solía hacerlo, sin embargo, si realmente confías en una precisión específica en tus flotadores, estás haciendo algo mal.Respuestas:
Esto me volvió loco por un momento hasta que finalmente encontré este error que le indica este RFC que dice
Y (énfasis mío)
En resumen, hay una nueva forma de hacer que PHP 7.1
json_encode
use el motor de precisión nuevo y mejorado. En php.ini necesitas cambiarserialize_precision
aserialize_precision = -1
Puede verificar que funciona con esta línea de comando
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Deberías conseguir
{"price":45.99}
fuente
G(precision)=-1
yPG(serialize_precision)=-1
también se puede usar en PHP 5.4serialize_precision = -1
. Con -1, este código seecho json_encode([528.56 * 100]);
imprime[52855.99999999999]
json_encode
problemaComo desarrollador de complementos, no tengo acceso general a la configuración php.ini de un servidor. Entonces, en base a la respuesta de Machavity, escribí este pequeño código que puede usar en su script PHP. Simplemente colóquelo encima del script y json_encode seguirá funcionando como de costumbre.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
En algunos casos es necesario establecer una variable más. Estoy agregando esto como una segunda solución porque no estoy seguro de si la segunda solución funciona bien en todos los casos en los que la primera solución ha demostrado funcionar.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
fuente
Estaba codificando valores monetarios y tenía cosas como
330.46
codificar330.4600000000000363797880709171295166015625
. Si no desea, o no puede, cambiar la configuración de PHP y conoce la estructura de los datos de antemano, hay una solución muy simple que funcionó para mí. Simplemente conviértalo en una cadena (ambos hacen lo mismo):$data['discount'] = (string) $data['discount']; $data['discount'] = '' . $data['discount'];
Para mi caso de uso, esta fue una solución rápida y efectiva. Solo tenga en cuenta que esto significa que cuando lo decodifique de nuevo desde JSON será una cadena, ya que estará envuelto entre comillas dobles.
fuente
Resolví esto estableciendo precisión y serialize_precision en el mismo valor (10):
ini_set('precision', 10); ini_set('serialize_precision', 10);
También puede configurar esto en su php.ini
fuente
Tuve el mismo problema, pero solo serialize_precision = -1 no resolvió el problema. Tuve que hacer un paso más para actualizar el valor de precisión de 14 a 17 (como estaba configurado en mi archivo ini PHP7.0). Aparentemente, cambiar el valor de ese número cambia el valor del flotador calculado.
fuente
Las otras soluciones no funcionaron para mí. Esto es lo que tuve que agregar al comienzo de la ejecución de mi código:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
fuente
En cuanto a mí, el problema fue cuando JSON_NUMERIC_CHECK como segundo argumento de json_encode () pasó, que convertía todos los números en int (no solo integer)
fuente
Guárdelo como una cadena con la precisión exacta que necesita usando
number_format
, luegojson_encode
use laJSON_NUMERIC_CHECK
opción:$foo = array('max' => number_format(472.185, 3, '.', '')); print_r(json_encode($foo, JSON_NUMERIC_CHECK));
Usted obtiene:
{"max": 472.185}
Tenga en cuenta que esto hará que TODAS las cadenas numéricas en su objeto de origen se codifiquen como números en el JSON resultante.
fuente
$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 }
fuente
Parece que el problema se produce cuando
serialize
yserialize_precision
se establecen en valores diferentes. En mi caso 14 y 17 respectivamente. Establecer ambos en 14 resolvió el problema, al igual que establecerserialize_precision
en -1.El valor predeterminado de
serialize_precision
se cambió a -1 a partir de PHP 7.1.0, lo que significa que "se utilizará un algoritmo mejorado para redondear dichos números". Pero si sigue experimentando este problema, puede deberse a que tiene un archivo de configuración PHP de una versión anterior. (¿Quizás guardó su archivo de configuración cuando actualizó?)Otra cosa a considerar es si tiene sentido usar valores flotantes en su caso. Puede que tenga sentido o no usar valores de cadena que contengan sus números para garantizar que siempre se conserve la cantidad adecuada de decimales en su JSON.
fuente
Puede cambiar el [max] => 472.185 de un flotante a una cadena ([max] => '472.185') antes del json_encode (). Como json es una cadena de todos modos, convertir sus valores flotantes en cadenas antes de json_encode () mantendrá el valor que desea.
fuente