这不是一个问题,因为它更需要注意。我更新了一个使用json_encode()
到PHP7.1.1的应用程序,我看到一个问题,浮动被更改为有时延伸出17位数。根据文档,PHP 7.1.x在编码double值时开始使用serialize_precision
而不是精度。我猜这导致了
472.185
成为
472.18500000000006
在该值经过json_encode()
之后。自从我的发现以来,我已经恢复到PHP 7.0.16并且我不再遇到json_encode()
的问题。我还尝试在恢复到PHP 7.0.16之前更新到PHP 7.1.2。
这个问题背后的原因确实源于PHP - Floating Number Precision,但最终所有原因都是因为json_encode()
中从精确度到serialize_precision用法的变化。
如果有人确实知道这个问题的解决方案,我会非常乐意听取推理/修复。
摘录自多维数组(之前):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
并在经过json_encode()
...
"staticYaxisInfo":
{
"17":
{
"variable_id": "17",
"static": "1",
"min": 0,
"max": 472.18500000000006,
"locked_static": "1"
}
},
答案 0 :(得分:64)
这让我疯了一会儿,直到我终于发现this bug指向你this RFC
目前
choices
使用设置为14的EG(精度)。这意味着最多14位用于显示(打印)该数字。 IEEE 754 double支持更高的精度,json_encode()
/serialize()
使用PG(serialize_precision),设置为17默认为更精确。由于var_export()
使用EG(精度),json_encode()
删除小数部分的低位数并破坏原始值,即使PHP的float可以保存更精确的浮点值。
并且(强调我的)
这个RFC建议引入一个新的设置EG(precision)= - 1和 PG(serialize_precision)= - 1,它使用zend_dtoa()的模式0,它使用更好的算法来舍入浮点数(-1是用来表示0模式)。
简而言之,有一种新方法可以使PHP 7.1 json_encode()
使用新的和改进的精确引擎。在 php.ini 中,您需要将json_encode
更改为
serialize_precision
您可以验证它是否适用于此命令行
serialize_precision = -1
你应该
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
答案 1 :(得分:16)
作为插件开发人员,我无法对服务器的php.ini设置进行常规访问。因此,根据Machavity的回答,我编写了一小段代码,您可以在PHP脚本中使用它。只需将其置于脚本之上,json_encode将继续照常工作。
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'serialize_precision', -1 );
}
答案 2 :(得分:3)
我有同样的问题,但只有serialize_precision = -1没有解决问题。我不得不再做一步,将精度值从14更新为17(因为它是在我的PHP7.0 ini文件中设置的)。显然,更改该数字的值会更改计算浮点数的值。
答案 3 :(得分:3)
其他解决方案对我没有用。这是我在代码执行开始时必须添加的内容:
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'precision', 17 );
ini_set( 'serialize_precision', -1 );
}
答案 4 :(得分:2)
我通过将precision和serialize_precision设置为相同的值(10)来解决了这个问题:
ini_set('precision', 10);
ini_set('serialize_precision', 10);
您也可以在php.ini中设置它
答案 5 :(得分:2)
在 php 7.2.32 上,解决方案是在 php.ini 中设置:
precision=10
serialize_precision=10
答案 6 :(得分:0)
我正在编码货币价值,并且将330.46
编码为330.4600000000000363797880709171295166015625
。如果您不希望或无法更改PHP设置,并且事先知道数据的结构,那么有一个非常简单的解决方案对我有用。只需将其转换为字符串即可(以下两者都做同样的事情):
$data['discount'] = (string) $data['discount'];
$data['discount'] = '' . $data['discount'];
对于我的用例,这是一种快速有效的解决方案。请注意,这意味着当您从JSON解码回来时,它将是一个字符串,因为它将用双引号引起来。
答案 7 :(得分:0)
您可以将[max] => 472.185从浮点数更改为json_encode()之前的字符串([max] =>'472.185')。由于json仍然是字符串,因此将您的float值转换为json_encode()之前的字符串将保持您想要的值。
答案 8 :(得分:0)
对我来说,问题是当JSON_NUMERIC_CHECK作为json_encode()的第二个参数传递时,该类型将所有数字强制转换为int(不仅是整数)
答案 9 :(得分:0)
使用number_format
将其存储为具有所需精确度的字符串,然后使用json_encode
选项将其JSON_NUMERIC_CHECK
存储:
$foo = array('max' => number_format(472.185, 3, '.', ''));
print_r(json_encode($foo, JSON_NUMERIC_CHECK));
您得到:
{"max": 472.185}
请注意,这会将源对象中的所有数字字符串转换为结果JSON中的数字。
答案 10 :(得分:0)
$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
}
答案 11 :(得分:0)
当serialize_precision
和serialize_precision
设置为不同的值时,似乎会出现问题。在我的情况下分别为14和17。将它们都设置为14可解决此问题,将serialize_precision
设置为-1也可以解决此问题。
{{1}} was changed to -1 as of PHP 7.1.0的默认值,这意味着“将使用用于舍入此类数字的增强算法”。但是,如果仍然遇到此问题,则可能是因为您有一个来自先前版本的PHP配置文件。 (也许升级后保留了配置文件?)
要考虑的另一件事是,在您的情况下完全使用浮点值是否有意义。使用包含数字的字符串值来确保始终在JSON中始终保留正确的小数位数可能没有意义。