Ce n'est pas une question car il s'agit plus d'un être conscient. J'ai mis à jour une application qui utilise json_encode()
PHP7.1.1 et je voyais un problème avec les flotteurs modifiés pour parfois étendre 17 chiffres. Selon la documentation, PHP 7.1.x a commencé à utiliser serialize_precision
au lieu de la précision lors de l'encodage de valeurs doubles. Je suppose que cela a causé un exemple de valeur de
472,185
devenir
472.18500000000006
après que cette valeur soit passée 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 PHP 7.1.2 avant de revenir à PHP 7.0.16.
Le raisonnement derrière cette question provient de PHP - Floating Number Precision , mais la fin de toute raison en est due au passage de la précision à l'utilisation de serialize_precision dans json_encode()
.
Si quelqu'un connaît une solution à ce problème, je serais plus qu'heureux d'écouter le raisonnement / la solution.
Extrait du 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"
}
},
ini_set('serialize_precision', 14); ini_set('precision', 14);
le ferait probablement sérialiser comme avant, mais si vous comptez vraiment sur une précision spécifique sur vos flotteurs, vous faites quelque chose de mal.Réponses:
Cela m'a rendu fou pendant un moment jusqu'à ce que je trouve enfin ce bogue qui vous renvoie à cette RFC qui dit
Et (c'est moi qui souligne)
En bref, il existe une nouvelle façon de faire en sorte que PHP 7.1
json_encode
utilise le nouveau moteur de précision amélioré. Dans php.ini, vous devez changerserialize_precision
pourserialize_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}
la source
G(precision)=-1
etPG(serialize_precision)=-1
peut également être utilisé en PHP 5.4serialize_precision = -1
. Avec -1, ce codeecho json_encode([528.56 * 100]);
imprime[52855.99999999999]
json_encode
problèmeEn tant que développeur de plugins, je n'ai pas d'accès général aux paramètres php.ini d'un serveur. Donc, sur la base de la réponse de Machavity, j'ai écrit ce petit morceau de code que vous pouvez utiliser dans votre script PHP. Mettez-le simplement au-dessus du script et json_encode continuera à fonctionner comme d'habitude.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
Dans certains cas, il est nécessaire de définir une autre variable. J'ajoute cela comme deuxième solution parce que je ne suis pas sûr que la deuxième solution fonctionne correctement dans tous les cas où la première solution s'est avérée efficace.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
la source
J'encodais des valeurs monétaires et j'avais des choses comme l'
330.46
encodage330.4600000000000363797880709171295166015625
. Si vous ne souhaitez pas ou ne pouvez pas modifier les paramètres PHP et que vous connaissez à l'avance la structure des données, il existe une solution très simple qui a fonctionné pour moi. Il suffit de le convertir en une chaîne (les deux opérations suivantes 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 elle sera entourée de guillemets doubles.
la source
J'ai résolu ce problème en définissant à la fois precision et serialize_precision sur la même valeur (10):
ini_set('precision', 10); ini_set('serialize_precision', 10);
Vous pouvez également définir cela dans votre php.ini
la source
J'ai eu le même problème mais seul serialize_precision = -1 n'a pas résolu le problème. J'ai dû faire une étape de plus, mettre à jour la valeur de précision de 14 à 17 (comme elle était définie sur mon fichier ini PHP7.0). Apparemment, changer la valeur de ce nombre change la valeur du flottant calculé.
la source
Les autres solutions n'ont pas fonctionné pour moi. Voici ce que j'avais à ajouter au début de mon exécution de code:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
la source
Quant à moi, le problème était lorsque JSON_NUMERIC_CHECK en tant que deuxième argument de json_encode () est passé, ce qui convertissait tous les types de nombres en int (pas seulement en entier)
la source
Stockez-le sous forme de chaîne avec la précision exacte dont vous avez besoin en utilisant
number_format
, puisjson_encode
en utilisant l'JSON_NUMERIC_CHECK
option:$foo = array('max' => number_format(472.185, 3, '.', '')); print_r(json_encode($foo, JSON_NUMERIC_CHECK));
Vous obtenez:
{"max": 472.185}
Notez que cela obtiendra TOUTES les chaînes numériques de votre objet source à encoder sous forme de nombres dans le JSON résultant.
la source
$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 }
la source
Il semble que le problème se produit lorsque
serialize
etserialize_precision
sont définis sur des valeurs différentes. Dans mon cas, 14 et 17 respectivement. Leur définition sur 14 a résolu le problème, tout comme la définitionserialize_precision
de -1.La valeur par défaut de a
serialize_precision
été changée en -1 à partir de PHP 7.1.0, ce qui signifie "un algorithme amélioré pour arrondir ces nombres sera utilisé". Mais si vous rencontrez toujours ce problème, c'est peut-être parce que vous avez un fichier de configuration PHP en place à partir d'une version antérieure. (Peut-être avez-vous conservé votre fichier de configuration lors de la mise à niveau?)Une autre chose à considérer est s'il est logique d'utiliser des valeurs flottantes dans votre cas. Il peut être judicieux ou non d'utiliser des valeurs de chaîne contenant vos nombres pour garantir que le nombre approprié de décimales est toujours conservé dans votre JSON.
la source
Vous pouvez changer le [max] => 472.185 d'un float en une chaîne ([max] => '472.185') avant le json_encode (). Comme json est de toute façon une chaîne, la conversion de vos valeurs flottantes en chaînes avant json_encode () maintiendra la valeur souhaitée.
la source