Esta não é uma pergunta, pois é mais uma questão de estar ciente. Atualizei um aplicativo que usa json_encode()
para PHP7.1.1 e estava vendo um problema com flutuações sendo alteradas para, às vezes, estender para 17 dígitos. De acordo com a documentação, o PHP 7.1.x passou a usar ao serialize_precision
invés da precisão ao codificar valores duplos. Estou supondo que isso causou um valor de exemplo de
472,185
tornar-se
472.18500000000006
depois que esse valor passou json_encode()
. Desde minha descoberta, voltei para o PHP 7.0.16 e não tenho mais problemas com o json_encode()
. Também tentei atualizar para o PHP 7.1.2 antes de voltar para o PHP 7.0.16.
O raciocínio por trás desta questão deriva de PHP - Floating Number Precision , no entanto, a razão final para isso é por causa da mudança do uso de precisão para serialize_precision em json_encode()
.
Se alguém souber de uma solução para este problema, ficaria mais do que feliz em ouvir o raciocínio / correção.
Trecho da matriz multidimensional (antes):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
e depois de passar 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);
provavelmente faria com que fosse serializado como costumava fazer, no entanto, se você realmente confia em uma precisão específica em seus flutuadores, está fazendo algo errado.Respostas:
Isso me deixou louco por um tempo, até que finalmente encontrei este bug que aponta para este RFC que diz
E (ênfase minha)
Resumindo, há uma nova maneira de fazer o PHP 7.1
json_encode
usar o novo e aprimorado mecanismo de precisão. No php.ini você precisa mudarserialize_precision
paraserialize_precision = -1
Você pode verificar se funciona com esta linha de comando
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Voce deveria pegar
{"price":45.99}
fonte
G(precision)=-1
ePG(serialize_precision)=-1
também pode ser usado no PHP 5.4serialize_precision = -1
. Com -1, este código éecho json_encode([528.56 * 100]);
impresso[52855.99999999999]
json_encode
problemaComo desenvolvedor de plugin, não tenho acesso geral às configurações do php.ini de um servidor. Então, com base na resposta de Machavity, escrevi este pequeno código que você pode usar em seu script PHP. Basta colocá-lo no topo do script e json_encode continuará funcionando normalmente.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
Em alguns casos, é necessário definir mais uma variável. Estou adicionando isso como uma segunda solução porque não tenho certeza se a segunda solução funciona bem em todos os casos em que a primeira solução provou funcionar.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
fonte
Resolvi isso definindo precisão e serialize_precision com o mesmo valor (10):
ini_set('precision', 10); ini_set('serialize_precision', 10);
Você também pode definir isso no seu php.ini
fonte
Eu estava codificando valores monetários e tinha coisas como
330.46
codificação para330.4600000000000363797880709171295166015625
. Se você não deseja ou não pode alterar as configurações do PHP e conhece a estrutura dos dados com antecedência, existe uma solução muito simples que funcionou para mim. Basta lançá-lo em uma corda (ambos fazem a mesma coisa):$data['discount'] = (string) $data['discount']; $data['discount'] = '' . $data['discount'];
Para o meu caso de uso, essa foi uma solução rápida e eficaz. Observe que isso significa que, quando você decodificá-lo de volta do JSON, será uma string, pois estará entre aspas duplas.
fonte
Eu tive o mesmo problema, mas apenas serialize_precision = -1 não resolveu o problema. Tive que fazer mais um passo, para atualizar o valor de precisão de 14 para 17 (como estava definido no meu arquivo PHP7.0 ini). Aparentemente, alterar o valor desse número altera o valor do float calculado.
fonte
As outras soluções não funcionaram para mim. Aqui está o que eu tive que adicionar no início da minha execução de código:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
fonte
Quanto a mim, o problema foi quando JSON_NUMERIC_CHECK como segundo argumento de json_encode () passou, o que converte todos os tipos de números em int (não apenas inteiro)
fonte
Armazene-o como uma string com a precisão exata de que você precisa usando e
number_format
, em seguidajson_encode
, use aJSON_NUMERIC_CHECK
opção:$foo = array('max' => number_format(472.185, 3, '.', '')); print_r(json_encode($foo, JSON_NUMERIC_CHECK));
Você obtém:
{"max": 472.185}
Observe que isso fará com que TODAS as strings numéricas em seu objeto de origem sejam codificadas como números no JSON resultante.
fonte
$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 }
fonte
Parece que o problema ocorre quando
serialize
eserialize_precision
são definidos com valores diferentes. No meu caso, 14 e 17, respectivamente. Definir ambos como 14 resolveu o problema, assim como definirserialize_precision
como -1.O valor padrão de
serialize_precision
foi alterado para -1 a partir do PHP 7.1.0, o que significa "um algoritmo aprimorado para arredondar esses números será usado". Mas se você ainda estiver enfrentando esse problema, pode ser porque você tem um arquivo de configuração do PHP de uma versão anterior. (Talvez você tenha mantido seu arquivo de configuração quando atualizou?)Outra coisa a considerar é se faz sentido usar valores flutuantes no seu caso. Pode ou não fazer sentido usar valores de string contendo seus números para garantir que o número adequado de casas decimais seja sempre mantido em seu JSON.
fonte
Você poderia mudar o [max] => 472.185 de um float para uma string ([max] => '472.185') antes do json_encode (). Como json é uma string de qualquer maneira, converter seus valores float em strings antes de json_encode () manterá o valor que você deseja.
fonte