Ini bukan pertanyaan karena lebih merupakan kewaspadaan. Saya memperbarui aplikasi yang menggunakan json_encode()
PHP7.1.1 dan saya melihat masalah dengan float yang diubah terkadang melebihi 17 digit. Menurut dokumentasi, PHP 7.1.x mulai digunakan serialize_precision
sebagai pengganti presisi saat mengenkode nilai ganda. Saya menduga ini menyebabkan nilai contoh
472.185
untuk menjadi
472.18500000000006
setelah nilai itu masuk json_encode()
. Sejak penemuan saya, saya telah kembali ke PHP 7.0.16 dan saya tidak lagi memiliki masalah dengan json_encode()
. Saya juga mencoba memperbarui ke PHP 7.1.2 sebelum kembali ke PHP 7.0.16.
Alasan di balik pertanyaan ini memang berasal dari PHP - Floating Number Precision , namun pada akhirnya semua alasan untuk ini adalah karena perubahan dari penggunaan presisi ke serialize_precision di json_encode()
.
Jika ada yang tahu solusi untuk masalah ini, saya akan dengan senang hati mendengarkan alasan / perbaikannya.
Kutipan dari array multidimensi (sebelum):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
dan setelah melalui 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);
mungkin akan membuatnya berseri seperti dulu, namun jika Anda benar-benar mengandalkan presisi tertentu pada float Anda, Anda melakukan sesuatu yang salah.Jawaban:
Ini membuat saya sedikit gila sampai akhirnya saya menemukan bug ini yang mengarahkan Anda ke RFC yang mengatakan
Dan (penekanan saya)
Singkatnya, ada cara baru untuk membuat PHP 7.1
json_encode
menggunakan mesin presisi yang baru dan lebih baik. Di php.ini Anda perlu mengubahserialize_precision
keserialize_precision = -1
Anda dapat memverifikasi bahwa itu berfungsi dengan baris perintah ini
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Kamu harus mendapatkan
{"price":45.99}
sumber
G(precision)=-1
danPG(serialize_precision)=-1
juga dapat digunakan di PHP 5,4serialize_precision = -1
. Dengan -1, kode iniecho json_encode([528.56 * 100]);
mencetak[52855.99999999999]
json_encode
masalahSebagai pengembang plugin, saya tidak memiliki akses umum ke pengaturan php.ini server. Jadi, berdasarkan jawaban Machavity saya menulis potongan kecil kode ini yang dapat Anda gunakan dalam skrip PHP Anda. Letakkan saja di atas skrip dan json_encode akan tetap berfungsi seperti biasa.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
Dalam beberapa kasus, perlu menetapkan satu variabel lagi. Saya menambahkan ini sebagai solusi kedua karena saya tidak yakin apakah solusi kedua berfungsi dengan baik dalam semua kasus di mana solusi pertama terbukti berhasil.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
sumber
Saya menyandikan nilai moneter dan memiliki hal-hal seperti
330.46
penyandian330.4600000000000363797880709171295166015625
. Jika Anda tidak ingin, atau tidak bisa, mengubah pengaturan PHP dan Anda mengetahui struktur datanya sebelumnya, ada solusi yang sangat sederhana yang berhasil untuk saya. Cukup lemparkan ke string (kedua hal berikut melakukan hal yang sama):$data['discount'] = (string) $data['discount']; $data['discount'] = '' . $data['discount'];
Untuk kasus penggunaan saya, ini adalah solusi yang cepat dan efektif. Perhatikan bahwa ini berarti ketika Anda mendekodekannya kembali dari JSON, itu akan menjadi string karena akan dibungkus dengan tanda kutip ganda.
sumber
Saya menyelesaikan ini dengan mengatur presisi dan serialize_precision ke nilai yang sama (10):
ini_set('precision', 10); ini_set('serialize_precision', 10);
Anda juga dapat mengatur ini di php.ini Anda
sumber
Saya memiliki masalah yang sama tetapi hanya serialize_precision = -1 yang tidak menyelesaikan masalah. Saya harus melakukan satu langkah lagi, untuk memperbarui nilai presisi dari 14 menjadi 17 (seperti yang ditetapkan pada file ini PHP7.0 saya). Rupanya, mengubah nilai angka itu mengubah nilai float yang dihitung.
sumber
Solusi lain tidak berhasil untuk saya. Inilah yang harus saya tambahkan di awal eksekusi kode saya:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
sumber
Bagi saya masalahnya adalah ketika JSON_NUMERIC_CHECK sebagai argumen kedua json_encode () berlalu, yang mentransmisikan semua jenis angka ke int (tidak hanya integer)
sumber
Simpan sebagai string dengan presisi yang Anda butuhkan dengan menggunakan
number_format
, lalujson_encode
gunakanJSON_NUMERIC_CHECK
opsi:$foo = array('max' => number_format(472.185, 3, '.', '')); print_r(json_encode($foo, JSON_NUMERIC_CHECK));
Anda mendapatkan:
{"max": 472.185}
Perhatikan bahwa ini akan membuat SEMUA string numerik di objek sumber Anda dienkode sebagai angka dalam JSON yang dihasilkan.
sumber
$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 }
sumber
Sepertinya masalah terjadi ketika
serialize
danserialize_precision
diatur ke nilai yang berbeda. Dalam kasus saya masing-masing 14 dan 17. Mengatur keduanya ke 14 menyelesaikan masalah, seperti halnya pengaturanserialize_precision
ke -1.Nilai default
serialize_precision
diubah menjadi -1 pada PHP 7.1.0 yang berarti "algoritma yang disempurnakan untuk pembulatan angka-angka seperti itu akan digunakan". Tetapi jika Anda masih mengalami masalah ini, itu mungkin karena Anda memiliki file konfigurasi PHP dari versi sebelumnya. (Mungkin Anda menyimpan file konfigurasi Anda saat meningkatkan?)Hal lain yang perlu dipertimbangkan adalah jika masuk akal untuk menggunakan nilai float sama sekali dalam kasus Anda. Mungkin masuk akal atau tidak untuk menggunakan nilai string yang berisi angka Anda untuk memastikan jumlah tempat desimal yang tepat selalu dipertahankan di JSON Anda.
sumber
Anda bisa mengubah [max] => 472.185 dari float menjadi string ([max] => '472.185') sebelum json_encode (). Karena json adalah string, mengonversi nilai float Anda ke string sebelum json_encode () akan mempertahankan nilai yang Anda inginkan.
sumber