PHP7.1 json_encode() 浮点问题

2022-08-30 07:06:10

这不是一个问题,因为它更像是一个意识。我更新了一个使用PHP7.1.1的应用程序,我看到浮点数被更改为有时扩展17位的问题。根据文档,PHP 7.1.x 开始在编码双精度值时使用代替精度。我猜这导致了一个示例值json_encode()serialize_precision

472.185

成为

472.18500000000006

在该值通过之后。自从我发现以来,我已经恢复到PHP 7.0.16,我不再有问题。在恢复到PHP 7.0.16之前,我还尝试更新到PHP 7.1.2。json_encode()json_encode()

这个问题背后的原因确实源于PHP - 浮点数精度,但是最终所有原因是因为从精度到serialize_precision用法的变化。json_encode()

如果有人知道这个问题的解决方案,我会非常乐意听听推理/修复。

摘自多维数组(之前):

[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"
                }
            },

答案 1

这让我抓狂了一会儿,直到我终于发现了这个错误,它指向这个RFC,它说

当前使用 EG(精度),设置为 14。这意味着最多使用14位数字来显示(打印)数字。IEEE 754 双精度和 / 使用 PG(serialize_precision),默认设置为 17 以更精确。由于使用EG(精度),删除分数部分的较低数字并破坏原始值,即使PHP的浮点数可以容纳更精确的浮点值。json_encode()serialize()var_export()json_encode()json_encode()

和(强调我的)

此 RFC 建议引入一个新的设置 EG(precision)=-1 和 PG(serialize_precision)=-1,该设置使用 zend_dtoa() 的模式 0,该模式使用更好的算法来舍入浮点数(-1 用于表示 0 模式)。

简而言之,有一种新的方法可以使PHP 7.1使用新的和改进的精度引擎。在 php 中.ini您需要更改为json_encodeserialize_precision

serialize_precision = -1

您可以验证它是否适用于此命令行

php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'

你应该得到

{"price":45.99}

答案 2

作为插件开发人员,我没有对服务器的php.ini设置的一般访问权限。因此,根据Machavity的回答,我写了这一小段代码,您可以在PHP脚本中使用。只需将其放在脚本之上,json_encode将继续照常工作。

if (version_compare(phpversion(), '7.1', '>=')) {
    ini_set( 'serialize_precision', -1 );
}

在某些情况下,有必要再设置一个变量。我将其添加为第二个解决方案,因为我不确定第二个解决方案是否在第一个解决方案已被证明有效的所有情况下都工作正常。

if (version_compare(phpversion(), '7.1', '>=')) {
    ini_set( 'precision', 17 );
    ini_set( 'serialize_precision', -1 );
}

推荐