Dies ist keine Frage, da es eher bewusst ist. Ich habe eine Anwendung aktualisiert, die json_encode()
PHP7.1.1 verwendet , und es wurde ein Problem festgestellt, bei dem Floats so geändert wurden, dass sie manchmal 17 Stellen umfassen. Laut Dokumentation wurde PHP 7.1.x serialize_precision
beim Codieren von Doppelwerten anstelle der Genauigkeit verwendet. Ich vermute, dies hat einen Beispielwert von verursacht
472,185
werden
472.18500000000006
nachdem dieser Wert durchgegangen ist json_encode()
. Seit meiner Entdeckung bin ich zu PHP 7.0.16 zurückgekehrt und habe kein Problem mehr mit json_encode()
. Ich habe auch versucht, auf PHP 7.1.2 zu aktualisieren, bevor ich wieder auf PHP 7.0.16 zurückkam.
Die Gründe für diese Frage stammen aus PHP - Floating Number Precision . Der Grund dafür liegt jedoch in der Änderung von Precision zu serialize_precision in json_encode()
.
Wenn jemand eine Lösung für dieses Problem kennt, würde ich gerne die Argumentation / Lösung anhören.
Auszug aus einem mehrdimensionalen Array (vorher):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
und nach dem Durchgehen 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);
würde es wahrscheinlich wie früher serialisieren lassen, aber wenn Sie sich wirklich auf eine bestimmte Präzision Ihrer Schwimmer verlassen, machen Sie etwas falsch.Antworten:
Das hat mich ein bisschen verrückt gemacht, bis ich endlich diesen Fehler gefunden habe, der Sie auf diesen RFC hinweist, der besagt
Und (Hervorhebung von mir)
Kurz gesagt, es gibt eine neue Möglichkeit, PHP 7.1
json_encode
dazu zu bringen, die neue und verbesserte Präzisions-Engine zu verwenden. In php.ini müssen Sie ändernserialize_precision
zuserialize_precision = -1
Sie können überprüfen, ob es mit dieser Befehlszeile funktioniert
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Du solltest bekommen
{"price":45.99}
quelle
G(precision)=-1
undPG(serialize_precision)=-1
kann auch in PHP 5.4serialize_precision = -1
. Mit -1echo json_encode([528.56 * 100]);
druckt dieser Code[52855.99999999999]
json_encode
Problem istAls Plugin-Entwickler habe ich keinen allgemeinen Zugriff auf die php.ini-Einstellungen eines Servers. Basierend auf Machavitys Antwort habe ich diesen kleinen Code geschrieben, den Sie in Ihrem PHP-Skript verwenden können. Setzen Sie es einfach oben auf das Skript und json_encode funktioniert wie gewohnt weiter.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
In einigen Fällen muss eine weitere Variable festgelegt werden. Ich füge dies als zweite Lösung hinzu, da ich nicht sicher bin, ob die zweite Lösung in allen Fällen gut funktioniert, in denen sich die erste Lösung als wirksam erwiesen hat.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
quelle
Ich verschlüsselte Geldwerte und hatte Dinge wie das
330.46
Kodieren330.4600000000000363797880709171295166015625
. Wenn Sie die PHP-Einstellungen nicht ändern möchten oder können und die Struktur der Daten im Voraus kennen, gibt es eine sehr einfache Lösung, die für mich funktioniert hat. Wirf es einfach in eine Zeichenfolge (beide folgenden tun dasselbe):$data['discount'] = (string) $data['discount']; $data['discount'] = '' . $data['discount'];
Für meinen Anwendungsfall war dies eine schnelle und effektive Lösung. Beachten Sie nur, dass dies bedeutet, dass es beim Dekodieren aus JSON eine Zeichenfolge ist, da es in doppelte Anführungszeichen gesetzt wird.
quelle
Ich habe dieses Problem gelöst, indem ich sowohl precision als auch serialize_precision auf denselben Wert gesetzt habe (10):
ini_set('precision', 10); ini_set('serialize_precision', 10);
Sie können dies auch in Ihrer php.ini einstellen
quelle
Ich hatte das gleiche Problem, aber nur serialize_precision = -1 hat das Problem nicht gelöst. Ich musste noch einen Schritt tun, um den Genauigkeitswert von 14 auf 17 zu aktualisieren (wie er in meiner PHP7.0-INI-Datei festgelegt wurde). Anscheinend ändert das Ändern des Werts dieser Zahl den Wert des berechneten Floats.
quelle
Die anderen Lösungen haben bei mir nicht funktioniert. Folgendes musste ich zu Beginn meiner Codeausführung hinzufügen:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
quelle
Was mich betrifft, war das Problem, als JSON_NUMERIC_CHECK als zweites Argument von json_encode () übergeben wurde, das alle Zahlen in int (nicht nur integer) umwandelte.
quelle
Speichern Sie es als Zeichenfolge mit der genauen Genauigkeit, die Sie benötigen
number_format
, und verwendenjson_encode
Sie dann die folgendeJSON_NUMERIC_CHECK
Option:$foo = array('max' => number_format(472.185, 3, '.', '')); print_r(json_encode($foo, JSON_NUMERIC_CHECK));
Du erhältst:
{"max": 472.185}
Beachten Sie, dass dadurch ALLE numerischen Zeichenfolgen in Ihrem Quellobjekt als Zahlen im resultierenden JSON codiert werden.
quelle
$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 }
quelle
Es scheint, dass das Problem auftritt, wenn
serialize
undserialize_precision
auf unterschiedliche Werte eingestellt sind. In meinem Fall 14 bzw. 17. Wenn Sie beide auf 14 setzen, wurde das Problem behoben, ebenso wie das Setzenserialize_precision
auf -1.Der Standardwert von
serialize_precision
wurde ab PHP 7.1.0 auf -1 geändert, was bedeutet, dass "ein erweiterter Algorithmus zum Runden solcher Zahlen verwendet wird". Wenn dieses Problem jedoch weiterhin auftritt, kann dies daran liegen, dass eine PHP-Konfigurationsdatei aus einer früheren Version vorhanden ist. (Vielleicht haben Sie Ihre Konfigurationsdatei beim Upgrade beibehalten?)Eine andere zu berücksichtigende Sache ist, ob es in Ihrem Fall sinnvoll ist, überhaupt Gleitkommawerte zu verwenden. Es kann sinnvoll sein, Zeichenfolgenwerte zu verwenden, die Ihre Zahlen enthalten, um sicherzustellen, dass die richtige Anzahl von Dezimalstellen in Ihrem JSON immer erhalten bleibt.
quelle
Sie können [max] => 472.185 von einem Float in einen String ([max] => '472.185') vor dem json_encode () ändern. Da json ohnehin eine Zeichenfolge ist, wird durch Konvertieren Ihrer Gleitkommawerte in Zeichenfolgen vor json_encode () der gewünschte Wert beibehalten.
quelle