2012-03-26 24 views
6

Tôi cố gắng tạo các trường hợp kiểm tra đơn vị để kiểm tra giá trị bảng của tôi là chính xác hoặc sai.vấn đề trong so sánh giá trị gấp đôi với php

Đây là mã của tôi

echo $a = 2/9; 
echo "<br>".$b=0.22222222222222; 

echo "<br>".gettype($a); 
echo "<br>".gettype($b); 
if($a==$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 


if((string)$a==(string)$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 

Tại sao tôi đầu tiên nếu tình trạng không làm việc? Tôi không thể tìm ra lý do. Làm ơn giúp tôi.

+2

Bản sao có thể có của http://stackoverflow.com/questions/3148937/compare-floats-in-php KHÔNG BAO GIỜ so sánh nổi với '=='. Ngoài ra '2/9' không phải là' 0.22222222222222'. Phần thập phân diễn ra vô hạn, do đó, so sánh của bạn sẽ thất bại ngay cả khi PHP đang tính toán nổi biểu tượng. – Basti

Trả lời

10

Bài kiểm tra vi phạm một quy tắc hồng y của chương trình điểm nổi: không bao giờ làm so sánh bình đẳng.

Có một số vấn đề xuất phát từ thực tế rằng các phân số dấu chấm động có số lượng bit lớn nhưng hữu hạn. Những vấn đề này thường được gọi là "lỗi làm tròn" mặc dù phần lớn chúng không phải là lỗi nhưng là giới hạn định dạng. Ví dụ, vì cách chúng ta viết số khi lập trình ... dưới dạng chuỗi thập phân ... hầu hết các số chúng ta có thể viết không có biểu diễn tương ứng trong định dạng dấu chấm động nếu chúng có phần thập phân. Phần phân đoạn lặp lại trong hai cơ sở.

Điều này phần lớn quy tắc so sánh chính xác số dấu phẩy động, ngoại trừ, trớ trêu thay, giữa các giá trị tích phân. Bạn cần phải thực hiện một sự so sánh mờ như abs(a - b) < epsilon.

Và trên thực tế, bạn 2/9 là một trường hợp độc đắc mà không có một đại diện hữu hạn như hoặc một chuỗi số thập phân hoặc một chuỗi nhị phân !

Để so sánh 2/9 thành công cho sự bình đẳng với các vị trí liên tục, các yêu cầu về hoàn thiện chương trình, thông dịch viên và thư viện nhiều hơn có thể được tính. Ví dụ, bạn sẽ phải nhập nhiều hơn 2 s so với nhu cầu của bạn và thông dịch viên phải làm tròn các bit thứ tự thấp của hằng số với kiến ​​thức về độ chính xác cao hơn định dạng có. Máy thực sự có một vài kiến ​​thức bổ sung khi thực hiện thao tác nhưng trình thông dịch có thể không khi chuyển đổi hằng số. Ngoài ra, làm tròn thời gian chạy là tùy thuộc vào các tùy chọn khác nhau và một ngôn ngữ như PHP thậm chí không thể xác định chính xác các hằng số không thể hiển thị được làm tròn từ mã nguồn sang dạng nội bộ.

Và thực tế nó là tồi tệ hơn hơn thế, bởi vì cá nhân 0.2/10 n thành phần trong chuỗi thập phân cũng không có tương đương nhị phân chính xác. Vì vậy, rất có khả năng chuyển đổi thực sự hoàn hảo và trung thành của 0.22222222222222 không không thực sự bằng một biểu diễn nỗ lực tốt nhất của 2/9 thực tế. Bạn không thể biểu diễn dưới dạng một chuỗi thập phân hữu hạn, phần chính xác cơ bản-2 đại diện chặt chẽ nhất cho 2/9 trong bất kỳ số bit cụ thể nào (hữu hạn).

(Chúng ta phải có một câu trả lời ở đâu đó tiêu chuẩn về việc không thực hiện so sánh ngang hàng với số dấu chấm động.)


1. Mỗi máy phần là một con số hợp lý các hình thức x/2 n . Bây giờ, hằng số là số thập phân và hằng số thập phân là một số hợp lý của biểu mẫu x/(2 n * 5 m). Số 5 m là số lẻ nên không có hệ số 2 n cho bất kỳ số nào trong số đó. Chỉ khi m == 0 có một biểu diễn hữu hạn trong cả phần mở rộng nhị phân và thập phân của phân số. Ví dụ, 1.25 là chính xác bởi vì nó là 5/(2 * 5) nhưng 0.1 được không phải vì nó là 1/(2 * 5). Và đối với số hữu tỉ 2/9, không có 2 nhoặc một hệ số 5 m.

3

Nếu bạn xem tài liệu PHP floating point numbers (bao gồm gấp đôi), bạn sẽ nhanh chóng thấy rằng khó so sánh khó có thể so sánh do bản chất của các số dấu phẩy động.

Vì vậy, không bao giờ tin tưởng các kết quả số thực trôi nổi đến chữ số cuối cùng và không so sánh trực tiếp số dấu phẩy động cho bình đẳng.

Các tài liệu cung cấp một ví dụ cũng như:

<?php 

$a = 1.23456789; 
$b = 1.23456780; 
$epsilon = 0.00001; 

if(abs($a-$b) < $epsilon) { 
    echo "true"; 
} 
4

Nổi khó, bạn cần giới hạn số điểm thập phân.

$a = 2/9; 
$b=0.22222222222222; 

$a = number_format($a, 9); 
$b = number_format($b, 9); 

echo "a = " . $a . " and b = " . $b; 

echo "<br>".gettype($a); 
echo "<br>".gettype($b); 
if($a==$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 


if((string)$a==(string)$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 
Các vấn đề liên quan