[php] PHP7.1 json_encode () 플로트 문제

이것은 더 잘 알고 있기 때문에 질문이 아닙니다. json_encode()PHP7.1.1 을 사용하는 응용 프로그램을 업데이트 했는데 수레가 때때로 17 자리를 확장하도록 변경되는 문제를 확인했습니다. 문서에 따르면 PHP 7.1.x는 serialize_precisiondouble 값을 인코딩 할 때 정밀도 대신 사용하기 시작했습니다 . 이로 인해 예제 값이 발생했다고 생각합니다.

472.185

472.18500000000006

그 값이 지나간 후에 json_encode(). 내 발견 이후로 PHP 7.0.16으로 되 돌렸고 더 이상 json_encode(). 또한 PHP 7.0.16으로 되돌리기 전에 PHP 7.1.2로 업데이트하려고했습니다.

이 질문에 대한 이유는 PHP 에서 비롯된 것입니다. 것이지만, 결국 모든 이유는 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"
                }
            },



답변

RFC 를 가리키는 이 버그 를 마침내 발견 할 때까지 이로 인해 잠시 미쳐 버렸습니다.

현재 json_encode()는 14로 설정된 EG (정밀도)를 사용하고 있습니다. 이는 최대 14 자리 숫자가 숫자를 표시 (인쇄)하는 데 사용된다는 의미입니다. IEEE 754 double은 더 높은 정밀도를 지원하고 serialize()/ var_export()는 더 정확한 17을 기본값으로 설정하는 PG (serialize_precision)를 사용합니다. json_encode()EG (precision)를 사용 하기 때문에 json_encode()PHP의 float가 더 정확한 float 값을 가질 수 있더라도 분수 부분의 하위 자릿수를 제거하고 원래 값을 파괴합니다.

그리고 (내 강조)

이 RFC 는 zend_dtoa ()의 모드 0을 사용 하는 새로운 설정 EG (precision) =-1 및 PG (serialize_precision) = -1을 도입 할 것을 제안합니다.이 모드는 부동 소수점 수를 반올림하는 데 더 나은 알고리즘을 사용합니다 (-1은 0 모드를 나타내는 데 사용됨). .

요컨대, PHP 7.1 json_encode이 새롭고 향상된 정밀 엔진을 사용 하도록 만드는 새로운 방법이 있습니다. 에서 php.ini의 당신은 변화를 필요 serialize_precision

serialize_precision = -1

이 명령 줄에서 작동하는지 확인할 수 있습니다.

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

당신은 얻어야한다

{"price":45.99}


답변

플러그인 개발자로서 저는 서버의 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 );
}


답변

나는 금전적 가치를 330.46인코딩하고 330.4600000000000363797880709171295166015625. PHP 설정을 변경하고 싶지 않거나 변경할 수없는 경우 데이터 구조를 미리 알고있는 경우 저에게 도움이되는 매우 간단한 솔루션이 있습니다. 단순히 문자열로 캐스트하십시오 (다음 두 가지 모두 동일한 작업을 수행함).

$data['discount'] = (string) $data['discount'];
$data['discount'] = '' . $data['discount'];

제 사용 사례에있어서 이것은 빠르고 효과적인 솔루션이었습니다. 이것은 JSON에서 다시 디코딩 할 때 큰 따옴표로 묶여 있기 때문에 문자열이됨을 의미합니다.


답변

정밀도와 serialize_precision을 동일한 값 (10)으로 설정하여이 문제를 해결했습니다.

ini_set('precision', 10);
ini_set('serialize_precision', 10);

php.ini에서 설정할 수도 있습니다.


답변

나는 같은 문제가 있었지만 serialize_precision = -1만이 문제를 해결하지 못했습니다. 정밀도 값을 14에서 17로 업데이트하기 위해 한 단계 더 수행해야했습니다 (내 PHP7.0 ini 파일에 설정 됨). 분명히 그 숫자의 값을 변경하면 계산 된 부동 소수점의 값이 변경됩니다.


답변

다른 솔루션은 저에게 효과적이지 않았습니다. 코드 실행을 시작할 때 추가해야 할 사항은 다음과 같습니다.

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


답변

나에게 문제는 json_encode ()의 두 번째 인수로 JSON_NUMERIC_CHECK가 전달되었을 때 모든 숫자 유형을 int (정수뿐만 아니라)로 캐스팅했습니다.