Khi so sánh các giá trị dấu phẩy động cho đẳng thức, có hai cách tiếp cận khác nhau:
NaN
không bằng chính nó, phù hợp với đặc điểm kỹ thuật của IEEE 754 .NaN
bằng chính nó, nó cung cấp tính chất toán học của tính phản xạ , điều cần thiết cho định nghĩa về mối quan hệ tương đương
Các kiểu dấu phẩy động tích hợp trong C # ( float
và double
) tuân theo ngữ nghĩa của IEEE cho ==
và !=
(và các toán tử quan hệ như <
) nhưng đảm bảo tính phản xạ cho object.Equals
, IEquatable<T>.Equals
(và CompareTo
).
Bây giờ hãy xem xét một thư viện cung cấp các cấu trúc vector trên đầu float
/ double
. Một loại vectơ như vậy sẽ quá tải ==
/ !=
và ghi đè object.Equals
/ IEquatable<T>.Equals
.
Điều mà mọi người đồng ý là ==
/ !=
nên tuân theo ngữ nghĩa của IEEE. Câu hỏi đặt ra là, liệu một thư viện như vậy có nên thực hiện Equals
phương thức (tách biệt với các toán tử đẳng thức) theo cách phản xạ hoặc theo cách phù hợp với ngữ nghĩa của IEEE.
Đối số sử dụng ngữ nghĩa của IEEE cho Equals
:
- Nó tuân theo IEEE 754
Nó (có thể nhiều) nhanh hơn vì nó có thể tận dụng các hướng dẫn SIMD
Tôi đã hỏi một câu hỏi riêng về stackoverflow về cách bạn thể hiện sự bình đẳng phản xạ bằng cách sử dụng các hướng dẫn SIMD và tác động hiệu suất của chúng: Hướng dẫn SIMD để so sánh đẳng thức dấu phẩy động
Cập nhật: Có vẻ như có thể thực hiện hiệu quả phản xạ bằng cách sử dụng ba hướng dẫn SIMD.
Tài liệu cho
Equals
không yêu cầu tính phản xạ khi liên quan đến dấu phẩy động:Các tuyên bố sau phải đúng với tất cả các cài đặt của phương thức Equals (Object). Trong danh sách,
x
,y
, vàz
đại diện cho tham chiếu đối tượng mà không phải là null.x.Equals(x)
trả vềtrue
, trừ trường hợp liên quan đến các loại dấu phẩy động. Xem ISO / IEC / IEEE 60559: 2011, Công nghệ thông tin - Hệ thống vi xử lý - Số học dấu phẩy động.Nếu bạn đang sử dụng phao làm khóa từ điển, bạn đang sống trong tình trạng tội lỗi và không nên mong đợi hành vi lành mạnh.
Đối số cho phản xạ:
Nó phù hợp với các loại hiện có, bao gồm
Single
,Double
,Tuple
vàSystem.Numerics.Complex
.Tôi không biết bất kỳ tiền lệ nào trong BCL,
Equals
theo sau IEEE thay vì phản xạ. Ví dụ Counter bao gồmSingle
,Double
,Tuple
vàSystem.Numerics.Complex
.Equals
chủ yếu được sử dụng bởi các container và thuật toán tìm kiếm dựa trên tính phản xạ. Đối với các thuật toán này, hiệu suất đạt được là không liên quan nếu ngăn chúng hoạt động. Đừng hy sinh tính đúng đắn cho hiệu suất.- Nó phá vỡ tất cả các bộ băm dựa và từ điển
Contains
,Find
,IndexOf
trên các bộ sưu tập khác nhau / LINQ, hoạt động thiết lập dựa trên LINQ (Union
,Except
, vv) nếu dữ liệu chứaNaN
giá trị. Mã thực hiện các tính toán thực tế trong đó ngữ nghĩa của IEEE được chấp nhận thường hoạt động trên các loại cụ thể và sử dụng
==
/!=
(hoặc nhiều khả năng so sánh epsilon).Hiện tại bạn không thể viết các tính toán hiệu suất cao bằng cách sử dụng tổng quát vì bạn cần các phép toán số học cho điều đó, nhưng chúng không có sẵn thông qua các giao diện / phương thức ảo.
Vì vậy, một
Equals
phương pháp chậm hơn sẽ không ảnh hưởng đến hầu hết các mã hiệu suất cao.Bạn có thể cung cấp một
IeeeEquals
phương thức hoặc mộtIeeeEqualityComparer<T>
trường hợp trong trường hợp bạn cần ngữ nghĩa của IEEE hoặc bạn cần có lợi thế về hiệu suất.
Theo tôi những lập luận này ủng hộ mạnh mẽ việc thực hiện phản xạ.
Nhóm CoreFX của Microsoft có kế hoạch giới thiệu một loại vectơ như vậy trong .NET. Không giống như tôi, họ thích giải pháp của IEEE , chủ yếu là do các lợi thế về hiệu suất. Vì một quyết định như vậy chắc chắn sẽ không được thay đổi sau khi phát hành cuối cùng, tôi muốn nhận được phản hồi từ cộng đồng, về những gì tôi tin là một sai lầm lớn.
float
/ double
và một số loại khác, ==
và Equals
đã khác. Tôi nghĩ rằng sự không nhất quán với các loại hiện có thậm chí còn khó hiểu hơn so với sự không nhất quán giữa ==
và Equals
bạn sẽ vẫn phải đối phó với các loại khác. 2) Khá nhiều tất cả các thuật toán / bộ sưu tập chung sử dụng Equals
và dựa vào tính phản xạ của nó để hoạt động (LINQ và từ điển), trong khi các thuật toán dấu phẩy động cụ thể thường sử dụng ==
khi chúng có được ngữ nghĩa của chúng.
Vector<float>
một "con thú" khác hơn là đơn giản float
hoặc double
. Theo biện pháp đó, tôi không thể thấy lý do Equals
hoặc ==
nhà điều hành tuân thủ các tiêu chuẩn của họ. Bạn tự nhủ: "Nếu bạn đang sử dụng phao làm khóa từ điển, bạn đang sống trong tình trạng tội lỗi và không nên mong đợi hành vi lành mạnh". Nếu một người lưu trữ NaN
trong một cuốn từ điển, thì đó là lỗi chết tiệt của chính họ vì đã sử dụng thực hành khủng khiếp. Tôi hầu như không nghĩ rằng nhóm CoreFX đã không nghĩ đến điều này. Tôi sẽ đi với một ReflexiveEquals
hoặc tương tự, chỉ vì lợi ích hiệu suất.
==
vàEquals
sẽ trả về các kết quả khác nhau. Nhiều lập trình viên cho rằng họ như vậy, và làm điều tương tự . Hơn nữa - nói chung, việc triển khai các toán tử đẳng thức gọiEquals
phương thức. Bạn đã lập luận rằng người ta có thể bao gồm mộtIeeeEquals
, nhưng người ta cũng có thể làm điều đó theo cách khác và bao gồm một đốiReflexiveEquals
xứng. KiểuVector<float>
-type có thể được sử dụng trong nhiều ứng dụng quan trọng về hiệu năng và nên được tối ưu hóa cho phù hợp.