2014-10-08 17 views
5

Trong kiến ​​thức cũ của tôi: khi chúng ta muốn kiểm tra xem một đôi hoặc phao bằng 0,0,
chúng tôi nên không ghi như thế này:
Trong C++ và Java hiện tại, kiểu kép và kiểu float: if (x == 0.0) là chính xác?

double x = 0.0; 
if (x == 0.0) System.out.println("yes"); 
else System.out.println("no"); 

Nhưng vài phút trước, tôi đã thử nó một lần nữa, dưới Java (1.7)C++ (Apple LLVM phiên bản 6.0), không có vấn đề gì để viết như thế! Tôi đã thử cả hai loại "double" và "float" theo Java và C++, tương ứng.

Câu hỏi của tôi:

  • đã làm tôi nhớ một cái gì đó, hoặc chúng ta thực sự có thể kiểm tra đôi hoặc nổi như rằng dưới Java hiện tại và C++.
  • Nếu có thể, chúng ta có thể thực hiện nó dưới phiên bản đầu của Java và C++ không?


Kết luận (dựa trên tất cả giúp):
Chúng tôi nên không sử dụng "phao == float hoặc double == kép" để kiểm tra xem hai phao hoặc hai đôi đều bình đẳng ( nếu chúng tôi muốn nhận được câu trả lời đúng), các lý do là trong tất cả các câu trả lời và bình luận của dưới.


Edition (Lần đầu tiên):
Cảm ơn bạn rất nhiều vì tất cả sự giúp đỡ!
Nhưng một phút trước, tôi chỉ cố gắng này dưới Java (1.7), tất cả các chương trình " ",
có vẻ như chúng ta thực sự có thể làm điều đó dưới Java hiện nay!

float x = 0.0f; 
if (x == 0) System.out.println("yes"); 
else System.out.println("no"); 

float y = 100.0f - 50.0f*2.0f + 45.0f*3 - 135.0f; 
if (y == 0.0f) System.out.println("yes"); 
else System.out.println("no"); 

if (100.0f - 50.0f*2.0f + 45.0f*3 - 135.0f == 0.0f) System.out.println("yes"); 
else System.out.println("no"); 


Edition (Second Time):
Nhưng tôi đã cố gắng này, Java cũng cho thấy " ", (theo Java (1.7)).
Tôi cố gắng loại bỏ "tính toán trước" của trình biên dịch và chia tính toán thành nhiều bước.

float a = 100.0f; 
float b = 50.0f; 
float c = 2.0f; 
float bc = b * c; 
System.out.println("b*c = " + bc); 

float d = 45.0f; 
float e = 3.0f; 
float de = d * e; 
System.out.println("d*e = " + de); 

float f = 135.0f; 

float g = a - bc + de - f; 
float h = 0.0f; 
if (g == h) System.out.println("yes"); 
else System.out.println("no"); 


Edition (lần thứ ba):
Cảm ơn bạn đã @ DiegoBasch của counterexample (đối với phao == float):
Lần này Java (1.7) hiển thị " no".

float m = 0.37f - 0.36f; 
float n = 0.01f; 
if (m - n == 0.0f) System.out.println("yes"); 
else System.out.println("no"); 
+13

'x' là chính xác' 0', vì vậy nó là OK. Vấn đề là khi 'x' là kết quả của một chuỗi các phép toán mà toán học sẽ mang lại' 0', nhưng không dẫn đến '0.0' vì các lý do số. – juanchopanza

+3

Để xây dựng trên những gì @juanchopanza nói, trong trường hợp của bạn sẽ đánh giá đúng, nhưng bạn không thể đảm bảo rằng '100.0 - 50.0 * 2.0 == 0.0' mặc dù toán học cần. – CoryKramer

+3

Các điểm nổi thường được mô tả là các giá trị "gần đúng", gây hiểu nhầm. Một số dấu chấm động có giá trị chính xác, nó chỉ là giá trị này có thể không chính xác những gì bạn mong đợi do độ chính xác hạn chế. Như vậy, nếu bạn so sánh nó với một giá trị kỳ vọng, bạn nên yêu cầu không "chúng giống hệt nhau" nhưng đúng hơn là chúng đủ gần. " '0.0' không khác với' 1.3' hoặc '3.14159' theo nghĩa đó. – yshavit

Trả lời

6

Mã này là hợp pháp. Vấn đề là khi bạn thực hiện các phép tính liên quan đến các số dấu phẩy động, sẽ có lỗi làm tròn, và do đó trong nhiều trường hợp kiểm tra chính xác 0 (hoặc kiểm tra hai số cho bình đẳng) sẽ không hoạt động.

Mã này là tốt bằng ngôn ngữ nào vì bạn đã không thực hiện bất cứ điều gì có thể gây ra làm tròn:

double x = 0.0; 
if (x == 0.0) System.out.println("yes"); 
else System.out.println("no"); 

Mã này có thể không tốt, mặc dù:

double a1 = ...something...; 
double a2 = ...something...; 
double a3 = a1/a2; 
double a4 = a3 * a2; 
double a5 = a4 - a1; 
if (a5 == 0.0) ... 

Mặc dù về mặt toán học a5 phải là 0, trong thực tế hoạt động == có thể trả lại false do làm tròn.

Điều này đòi hỏi sự hiểu biết về cách xử lý dấu phẩy động trong máy tính; nó không liên quan gì đến bất kỳ ngôn ngữ hoặc phiên bản ngôn ngữ nào. Một tham chiếu là What Every Computer Scientist Should Know About Floating-Point.

+4

[Trang web này] (http://floating-point-gui.de/) thường được trích dẫn là "giấy của Goldberg ở dạng tiêu hóa". – Angew

+0

Hi @ajb, cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn, nhưng tôi đã thử nó với một số tính toán dưới Java (1.7) nó hoạt động ..... xem ấn bản của tôi, có vẻ như chúng tôi thực sự có thể làm điều đó dưới Java bây giờ. – Zhaonan

+0

@Zhaonan xem nhận xét của tôi để phản hồi chỉnh sửa của bạn. '==' sẽ làm việc với các số _some_ và luôn luôn như vậy. Nó sẽ không hoạt động trong mọi trường hợp. Nó không liên quan gì đến phiên bản Java. – ajb

2

Để bổ sung câu trả lời của ajb, đây là ví dụ về lỗi số. Bạn không cần nhiều tính toán để nó xảy ra.

double a = 0.37 - 0.36; // 0.010000000000000009 
    double b = 0.01; 
    System.out.println (a - b == 0.0); // false 
+0

Xin chào @Diego Basch, cảm ơn bạn rất nhiều cho counterexample của bạn, bây giờ tôi tin rằng "float == float" sẽ không hoạt động trong mọi trường hợp. – Zhaonan

Các vấn đề liên quan