When comparing floating point values for equality, there are two different approaches:NaN not being equal to itself, which matches the IEEE 754 specification.NaN being equal to itself, which provides the mathematical property of Reflexivity which is essential to the definition of an Equivalence relationThe built in IEEE floating point types in C# (float and double) follow IEEE semantics for == and != (and the relational operators like <) but ensure reflexivity for object.Equals, IEquatable<T>.Equals (and CompareTo).Now consider a library that provides vector structs on top of float/double. Such a vector type would overload ==/!= and override object.Equals/IEquatable<T>.Equals.What everybody agrees on is that ==/!= should follow IEEE semantics. The question is, should such a library implement the Equals method (which is separate from the equality operators) in a way that's reflexive or in a way that matches the IEEE semantics.Arguments for using IEEE semantics for Equals:It follows IEEE 754It's (possibly much) faster because it can take advantage of SIMD instructionsI've asked a separate question on stackoverflow about how you'd express reflexive equality using SIMD instructions and their performance impact: SIMD instructions for floating point equality comparisonUpdate: It seems like it's possible to implement reflexive equality efficiently using three SIMD instructions.The documentation for Equals doesn't require reflexivity when involving floating point:The following statements must be true for all implementations of the Equals(Object) method. In the list, x, y, and z represent object references that are not null.x.Equals(x) returns true, except in cases that involve floating-point types. See ISO/IEC/IEEE 60559:2011, Information technology -- Microprocessor Systems -- Floating-Point arithmetic.If you're using floats as dictionary keys you're living in a state of sin and should not expect sane behaviour.Arguments for being reflexive:It's consistent with existing types, including Single, Double, Tuple and System.Numerics.Complex.I don't know any precedent in the BCL where Equals follows IEEE instead of being reflexive. Counter examples include Single, Double, Tuple and System.Numerics.Complex.Equals is mostly used by containers and search algorithms which rely on reflexivity. For these algorithms a performance gain is irrelevant if prevents them from working. Don't sacrifice correctness for performance.It breaks all hash based sets and dictionaries, Contains, Find, IndexOf on various collections/LINQ, set based LINQ operations (Union, Except, etc.) if the data contains NaN values.Code that does actual computations where IEEE semantic is acceptable usually works on concrete types and uses == / != (or more likely epsilon comparisons).You currently can't write high performance computations using generics since you need arithmetic operations for that, but these aren't available through interfaces/virtual methods.So a slower Equals method wouldn't affect most high performance code.It's possible to provide an IeeeEquals method or an IeeeEqualityComparer<T> for the cases where you either need the IEEE semantics or you need to performance advantage.In my opinion these arguments strongly favour a reflexive implementation.Microsoft's CoreFX team plans to introduce such a vector type in .NET. Unlike me they prefer the IEEE solution, mainly due to the performance advantages. Since such a decision certainly won't be changed after a final release, I want to get feedback from the community, on what I believe to be a big mistake.
Should `Vector.Equals` be reflexive or should it follow IEEE 754 semantics?
c#;.net;math;floating point