Ce n'est pas une question car c'est plus une conscience. J'ai mis à jour une application qui utilise json_encode()
en PHP 7.1.1 et je constatais un problème de modification des flotteurs, qui pouvait parfois être étendu à 17 chiffres. Selon la documentation, PHP 7.1.x a commencé à utiliser serialize_precision
au lieu de précision lors du codage de valeurs doubles. Je suppose que cela a causé une valeur d'exemple de
472.185
devenir
472.18500000000006
après que cette valeur soit passée par json_encode()
. Depuis ma découverte, je suis revenu à PHP 7.0.16 et je n'ai plus le problème avec json_encode()
. J'ai également essayé de mettre à jour vers PHP 7.1.2 avant de revenir à PHP 7.0.16.
Le raisonnement sous-jacent à cette question découle de PHP - Floating Number Precision , cependant, la raison en est le passage de la précision à la sérialisation_precision dans json_encode()
.
Si quelqu'un connaît une solution à ce problème, je serais ravi d'écouter le raisonnement/la solution.
Extrait de tableau multidimensionnel (avant):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
et après avoir traversé json_encode()
...
"staticYaxisInfo":
{
"17":
{
"variable_id": "17",
"static": "1",
"min": 0,
"max": 472.18500000000006,
"locked_static": "1"
}
},
Cela m’a un peu rendu fou jusqu’à ce que j’ai enfin trouvé ce bug qui vous indique ce RFC qui dit
Actuellement,
json_encode()
utilise EG (précision), qui est réglé sur 14. Cela signifie que 14 chiffres au maximum sont utilisés pour afficher (imprimer) le numéro. IEEE 754 double prend en charge une précision plus élevée etserialize()
var_export()
utilise PG (serialize_precision) qui est défini sur 17 par défaut pour être plus précis. Étant donné quejson_encode()
utilise EG (précision),json_encode()
supprime les chiffres inférieurs des fractions et détruit la valeur d'origine même si la valeur float de PHP peut contenir une valeur float plus précise.
Et (c'est moi qui souligne)
Cette RFC propose d’introduire un nouveau paramètre EG (précision) = - 1 et _/PG (serialize_precision) = - 1 qui utilise le mode 0 de zend_dtoa () qui utilise un meilleur algorithme pour arrondir les nombres à virgule flottante (-1 sert à indiquer 0 mode).
En bref, il existe un nouveau moyen de faire en sorte que PHP 7.1 json_encode
utilise le nouveau moteur de précision amélioré. Dans php.ini, vous devez remplacer serialize_precision
par
serialize_precision = -1
Vous pouvez vérifier que cela fonctionne avec cette ligne de commande
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Tu devrais obtenir
{"price":45.99}
En tant que développeur de plug-in, je n'ai pas d'accès général aux paramètres php.ini d'un serveur. Donc, basé sur la réponse de Machavity, j'ai écrit ce petit morceau de code que vous pouvez utiliser dans votre script PHP. Il suffit de le placer en haut du script et json_encode continuera à fonctionner normalement.
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'serialize_precision', -1 );
}
Les autres solutions ne fonctionnaient pas pour moi. Voici ce que je devais ajouter au début de l'exécution de mon code:
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'precision', 17 );
ini_set( 'serialize_precision', -1 );
}
J'ai eu le même problème mais seul serialize_precision = -1 n'a pas résolu le problème. Je devais faire encore une étape, pour mettre à jour la valeur de précision de 14 à 17 (comme elle était définie sur mon fichier in7 PHP7.0). Apparemment, changer la valeur de ce nombre change la valeur du float calculé.
J'ai résolu ce problème en définissant à la fois la précision et serialize_precision (10):
ini_set('precision', 10);
ini_set('serialize_precision', 10);
Vous pouvez également définir cela dans votre php.ini
Quant à moi, le problème était quand JSON_NUMERIC_CHECK en tant que second argument de json_encode () était passé, ce qui transtypait tout type de nombres en int (pas seulement un entier).
J'encodais des valeurs monétaires et j'avais des choses comme 330.46
encoding to 330.4600000000000363797880709171295166015625
. Si vous ne souhaitez pas ou ne pouvez pas modifier les paramètres PHP et si vous connaissez la structure des données à l'avance, il existe une solution très simple qui a fonctionné pour moi. Il suffit de le lancer dans une chaîne (les deux suivants font la même chose):
$data['discount'] = (string) $data['discount'];
$data['discount'] = '' . $data['discount'];
Pour mon cas d'utilisation, c'était une solution rapide et efficace. Notez simplement que cela signifie que lorsque vous le décodez à partir de JSON, ce sera une chaîne car il sera entouré de guillemets.
Vous pouvez changer le [max] => 472.185 d'un float en une chaîne ([max] => '472.185') avant json_encode () Comme json est quand même une chaîne, convertir vos valeurs float en chaînes avant json_encode () conservera la valeur souhaitée.