Cách phù hợp để so sánh System.Double to '0' (a number, int?)


87

Xin lỗi, đây có thể là một câu hỏi ngu ngốc dễ dàng, nhưng tôi cần biết để chắc chắn.

Tôi có ifbiểu hiện này ,

void Foo()
{
    System.Double something = GetSomething();
    if (something == 0) //Comparison of floating point numbers with equality 
                     // operator. Possible loss of precision while rounding value
        {}
}

Biểu thức đó có bằng

void Foo()
{
    System.Double something = GetSomething();
    if (something < 1)
        {}
}

? Vì sau đó tôi có thể gặp sự cố, nhập ifgiá trị ví dụ: 0,9.


3
// Comparison of floating point numbers with equality // operator. Bạn có thực sự cần xác định điều đó không? :)
George Johnston

1
Quái gì không. Có rất nhiều giá trị từ 0 đến 1. Tại sao không thử nghiệm nó và tự mình xem?
Igby Largeman

12
Tôi chỉ viết giống như Resharper đã làm, để cho biết trọng tâm của tôi ở đâu.
radbyx

@Charles: Ngoài ra, có rất nhiều con số đó là ít hơn 0.
Brian

có thể trùng lặp của So sánh giá trị đôi trong C #
Dzyann

Câu trả lời:


114

Chà, bạn cần giá trị gần bằng 0 đến mức nào? Nếu bạn thực hiện nhiều phép toán dấu phẩy động mà với "độ chính xác vô hạn" có thể dẫn đến kết quả là 0, bạn có thể nhận được kết quả "rất gần" với 0.

Thông thường trong tình huống này, bạn muốn cung cấp một số loại epsilon và kiểm tra xem kết quả có nằm trong epsilon đó không:

if (Math.Abs(something) < 0.001)

Epsilon bạn nên sử dụng là ứng dụng cụ thể - nó phụ thuộc vào những gì bạn đang làm.

Tất nhiên, nếu kết quả chính xác là 0, thì một phép kiểm tra bằng đơn giản là tốt.


Trên thực tế, tôi cần nó chính xác bằng 0, nó sẽ trông như thế nào? Tôi đã tìm Double.Zero, nhưng biết may mắn. Có một quyền không đổi? Btw, cảm ơn, tôi nhận được một phần epsilon bây giờ :)
radbyx

24
@radbyx: Chỉ cần sử dụng == 0. Bạn đã có một chữ có - đó là liên tục khá :)
Jon Skeet

35

Nếu somethingđã được chỉ định từ kết quả của một hoạt động khác something = 0thì tốt hơn bạn nên sử dụng:

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

Chỉnh sửa : Mã này sai. Epsilon là con số nhỏ nhất, nhưng không hoàn toàn bằng 0. Khi bạn muốn so sánh một số với một số khác, bạn cần nghĩ đến dung sai có thể chấp nhận được là bao nhiêu. Giả sử rằng bất cứ điều gì ngoài 0,00001 mà bạn không quan tâm. Đó là số bạn sẽ sử dụng. Giá trị phụ thuộc vào miền. Tuy nhiên, nó chắc chắn không bao giờ Double.Epsilon.


2
Điều này không giải quyết vấn đề làm tròn, ví dụ Math.Abs(0.1f - 0.1d) < double.Epsilonfalse
Thomas Lule

6
Double.Epsilon quá nhỏ để so sánh như vậy. Double.Epsilon là số dương nhỏ nhất mà double có thể biểu diễn.
Evgeni Nabokov

3
Điều này làm cho không có ý nghĩa vì nó là thực tế giống như so sánh với 0. -1
Gaspa79

1
Mục đích là để so sánh với khái niệm 0 mà không sử dụng dấu ==. Ít nhất thì nó cũng có ý nghĩa về mặt toán học. Tôi giả sử bạn có một nhân đôi trong tầm tay và bạn muốn so sánh nó với khái niệm số 0 mà không có dấu ==. Nếu giá trị kép của bạn khác 0d vì bất kỳ lý do gì, kể cả việc làm tròn, thì giá trị điền vào kiểm tra trả về false. Sự so sánh này có vẻ hợp lệ với bất kỳ đôi nào và sẽ chỉ trả về true nếu đôi này nhỏ nhất hơn số nhỏ nhất có thể được biểu diễn, đây có vẻ là một định nghĩa tốt để kiểm tra khái niệm 0, phải không?
sonatique

3
@MaurGi: bạn nhầm rồi: double d = Math.Sqrt(10100)*2; double a = Math.Sqrt(40400); if(Math.Abs(a - d) < double.Epsilon) { Console.WriteLine("true"); }
sonatique

26

Của bạn somethinglà a double, và bạn đã xác định chính xác điều đó trong dòng

if (something == 0)

chúng ta có một doubleở bên trái (lhs) và một intở bên phải (rhs).

Nhưng bây giờ có vẻ như bạn nghĩ rằng lhs sẽ được chuyển đổi thành an int, và sau đó ==dấu sẽ so sánh hai số nguyên. Đó không phải là những gì xảy ra. Việc chuyển đổi từ double thành intrõ ràng và không thể xảy ra "tự động".

Thay vào đó, điều ngược lại xảy ra. Rhs được chuyển đổi thành double, và sau đó ==dấu hiệu trở thành một bài kiểm tra bằng nhau giữa hai bộ đôi. Chuyển đổi này là ngầm định (tự động).

Nó được coi là tốt hơn (bởi một số) để viết

if (something == 0.0)

hoặc là

if (something == 0d)

bởi vì ngay lập tức rằng bạn đang so sánh hai đôi. Tuy nhiên, đó chỉ là vấn đề về phong cách và khả năng đọc vì trình biên dịch sẽ làm điều tương tự trong mọi trường hợp.

Trong một số trường hợp, việc đưa ra một "sự khoan dung" như trong câu trả lời của Jon Skeet cũng có liên quan, nhưng sự khoan dung đó cũng sẽ là một double. Tất nhiên nó có thể1.0nếu bạn muốn, nhưng nó không nhất thiết phải là số nguyên [ít dương nhất].


17

Nếu bạn chỉ muốn loại bỏ cảnh báo, hãy làm như sau:

if (something.Equals(0.0))

Tất nhiên, đây chỉ là một giải pháp hợp lệ nếu bạn biết rằng sự trôi dạt không phải là một mối quan tâm. Tôi thường làm điều này để kiểm tra xem tôi có sắp chia hết cho số không.


4

Tôi không nghĩ nó bình đẳng, thành thật mà nói. Hãy xem xét ví dụ của riêng bạn: something = 0.9 hoặc 0.0004. Trong trường hợp đầu tiên nó sẽ là FALSE, trong trường hợp thứ hai nó sẽ là TRUE. Đối phó với các loại này, tôi thường xác định cho tôi tỷ lệ phần trăm chính xác và so sánh trong độ chính xác đó. Tùy thuộc vào nhu cầu của bạn. cái gì đó như...

if(((int)(something*100)) == 0) {


//do something
}

Hi vọng điêu nay co ich.


2
một cái gì đó phải chính xác bằng không.
radbyx

vì vậy bạn anh chàng may mắn, trong trường hợp này :)
Tigran

3

Đây là ví dụ trình bày vấn đề (được chuẩn bị trong LinQPad - nếu bạn không có nó, chỉ cần sử dụng phương pháp Console.Writelinethay vì Dump):

void Main()
{
    double x = 0.000001 / 0.1;
    double y = 0.001 * 0.01; 

    double res = (x-y);
    res.Dump();
    (res == 0).Dump();
}

Về mặt lý thuyết, cả x và y đều giống nhau và bằng: 0,00001 nhưng do thiếu "độ chính xác vô hạn" nên các giá trị này hơi khác nhau. Thật không may, đủ để trở lại falsekhi so sánh với 0 theo cách thông thường.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.