2017-03-23 18 views
18

Đây không phải là một câu hỏi vì nó là một nhận thức rõ hơn. Tôi đã cập nhật một ứng dụng sử dụng json_encode() thành PHP7.1.1 và tôi đã nhìn thấy một vấn đề với phao được thay đổi để đôi khi kéo dài 17 chữ số. Theo tài liệu, PHP 7.1.x bắt đầu sử dụng serialize_precision thay vì chính xác khi mã hóa các giá trị kép. Tôi đoán điều này gây ra một giá trị ví dụ vềPHP7.1 json_encode() Float Issue

472,185

để trở thành

472,18500000000006

sau khi giá trị đó đã trải qua json_encode(). Kể từ khi khám phá của tôi, tôi đã hoàn nguyên về PHP 7.0.16 và tôi không còn gặp vấn đề với json_encode() nữa. Tôi cũng đã cố gắng cập nhật lên PHP 7.1.2 trước khi hoàn nguyên về PHP 7.0.16.

Lý do đằng sau câu hỏi này xuất phát từ PHP - Floating Number Precision, tuy nhiên, lý do cuối cùng là vì sự thay đổi từ độ chính xác sang sử dụng serialize_precision trong json_encode().

Nếu có ai biết giải pháp cho vấn đề này, tôi rất sẵn lòng lắng nghe lý do/khắc phục.

Trích từ mảng đa chiều (trước đó):

[staticYaxisInfo] => Array 
        (
         [17] => stdClass Object 
          (
           [variable_id] => 17 
           [static] => 1 
           [min] => 0 
           [max] => 472.185 
           [locked_static] => 1 
          ) 

        ) 

và sau khi đi qua json_encode() ...

"staticYaxisInfo": 
      { 
       "17": 
       { 
        "variable_id": "17", 
        "static": "1", 
        "min": 0, 
        "max": 472.18500000000006, 
        "locked_static": "1" 
       } 
      }, 
+1

'ini_set ('serialize_precision', 14); ini_set ('precision', 14); 'có lẽ sẽ làm cho nó tuần tự hóa như nó đã từng sử dụng, tuy nhiên nếu bạn thực sự dựa vào độ chính xác cụ thể trên phao bạn đang làm gì đó sai. – apokryfos

+0

Giá trị mặc định là 17, nhưng tôi đã đổi thành -1 để có "thuật toán nâng cao". Không có con xúc xắc. – Gwi7d31

+1

* "Nếu có ai biết giải pháp cho vấn đề này" * - có vấn đề gì? Tôi không thể thấy bất kỳ vấn đề nào ở đây. Nếu bạn giải mã JSON bằng cách sử dụng PHP, bạn lấy lại giá trị bạn đã mã hóa. Và nếu bạn giải mã nó bằng một ngôn ngữ khác, có lẽ bạn sẽ nhận được cùng một giá trị. Dù bằng cách nào, nếu bạn in giá trị bằng 12 chữ số, bạn sẽ nhận được giá trị ban đầu ("đúng"). Bạn có cần nhiều hơn 12 chữ số thập phân chính xác cho các phao được ứng dụng của bạn sử dụng không? – axiac

Trả lời

26

này chở tôi hạt cho một chút cho đến khi cuối cùng tôi đã tìm thấy this bug mà chỉ bạn this RFC có nội dung

Hiện tại json_encode() sử dụng EG (độ chính xác) được đặt thành 14. Điều đó có nghĩa là 14 chữ số nhiều nhất được sử dụng để hiển thị (in) số. IEEE 754 đôi hỗ trợ độ chính xác cao hơn và serialize()/var_export() sử dụng PG (serialize_precision) đặt thành 17 mặc định là chính xác hơn. Kể từ khi json_encode() sử dụng EG (độ chính xác), json_encode() loại bỏ các chữ số thấp hơn của các phần phân đoạn và phá hủy giá trị ban đầu ngay cả khi float của PHP có thể giữ giá trị float chính xác hơn.

Và (tôi nhấn mạnh)

RFC này đề xuất để giới thiệu một thiết lập mới EG (chính xác) = - 1 và PG (serialize_precision) = - 1 có sử dụng zend_dtoa() 's chế độ 0 sử dụng thuật toán tốt hơn để làm tròn số phao (-1 được sử dụng để chỉ ra chế độ 0).

Tóm lại, có một cách mới để làm cho PHP 7.1 json_encode sử dụng công cụ chính xác mới và được cải thiện. Trong số php.ini bạn cần thay đổi serialize_precision để

serialize_precision = -1 

Bạn có thể xác minh nó làm việc với dòng lệnh này

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

Bạn sẽ nhận được

{"price":45.99} 
4

Là một nhà phát triển plugin của tôi không có truy cập chung vào cài đặt php.ini của máy chủ. Vì vậy, dựa trên câu trả lời của Machavity, tôi đã viết đoạn mã nhỏ này mà bạn có thể sử dụng trong tập lệnh PHP của mình. Đơn giản chỉ cần đặt nó trên đầu trang của kịch bản và json_encode sẽ tiếp tục làm việc như bình thường.

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

Tôi đã gặp vấn đề tương tự nhưng chỉ serialize_precision = -1 không giải quyết được sự cố. Tôi đã phải thực hiện thêm một bước nữa, để cập nhật giá trị của độ chính xác từ 14 đến 17 (vì nó đã được thiết lập trên tệp ini PHP7.0 của tôi). Rõ ràng, việc thay đổi giá trị của số đó thay đổi giá trị của phao tính toán.

1

Các giải pháp khác không hiệu quả đối với tôi. Dưới đây là những gì tôi phải thêm vào lúc bắt đầu thực thi mã của mình:

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