Equals method behavior change for NaN
The Equals(T other)
instance method for the following types was updated to meet the IEquatable<T> implementation requirements. As a result, the method now correctly handles NaN. This change ensures the types can correctly be used alongside GetHashCode
, Dictionary<TKey,TValue>, and other hash sets.
- System.Numerics.Matrix3x2
- System.Numerics.Matrix4x4
- System.Numerics.Plane
- System.Numerics.Quaternion
- System.Numerics.Vector2
- System.Numerics.Vector3
- System.Numerics.Vector4
- System.Numerics.Vector<T>
- System.Runtime.Intrinsics.Vector64<T>
- System.Runtime.Intrinsics.Vector128<T>
- System.Runtime.Intrinsics.Vector256<T>
Previous behavior
Previously, the Equals(T other)
instance method followed the IEEE 754 requirements and deferred to the ==
implementation. This meant that NaN != NaN
, even when the two NaN are bitwise identical.
For example:
float f = float.NaN;
Console.WriteLine(f == f); // False
Console.WriteLine(f.Equals(f)); // True
While for several of the listed types:
Vector2 v = new Vector2(float.NaN);
Console.WriteLine(v == v); // False
Console.WriteLine(v.Equals(v)); // False
This is problematic because using one of these types as a key in a dictionary meant that the key could never be resolved:
Vector2 v = new Vector2(float.NaN);
var s = new HashSet<Vector2>();
s.Add(v);
Console.WriteLine(s.Contains(v)); // False
New behavior
The behavior is now the same as for the primitive floating-point types, which is that the ==
and !=
methods continue to follow the IEEE 754 requirements where NaN != NaN
. But the Equals(T other)
instance methods follow the IEquatable<T> requirements so that NaN.Equals(NaN)
.
For example (no change):
float f = float.NaN;
Console.WriteLine(f == f); // False
Console.WriteLine(f.Equals(f)); // True
While for several of the listed types (the second line now prints True
):
Vector2 v = new Vector2(float.NaN);
Console.WriteLine(v == v); // False
Console.WriteLine(v.Equals(v)); // True
And when used in some hash set (the output now prints True
):
Vector2 v = new Vector2(float.NaN);
var s = new HashSet<Vector2>();
s.Add(v);
Console.WriteLine(s.Contains(v)); // True
Version introduced
.NET 7
Type of breaking change
This change can affect binary compatibility.
Reason for change
The previous implementation did not meet the implementation requirements of IEquatable<T> or object.Equals(object obj)
. This resulted in the affected types not being usable in hash sets or with GetHashCode
.
Recommended action
If you prefer the previous behavior, switch to using ==
or !=
instead of Equals(T other)
.
Affected APIs
- System.Numerics.Matrix3x2.Equals
- System.Numerics.Matrix4x4.Equals
- System.Numerics.Plane.Equals
- System.Numerics.Quaternion.Equals
- System.Numerics.Vector2.Equals
- System.Numerics.Vector3.Equals
- System.Numerics.Vector4.Equals
- System.Numerics.Vector<T>.Equals
- System.Runtime.Intrinsics.Vector64<T>.Equals
- System.Runtime.Intrinsics.Vector128<T>.Equals
- System.Runtime.Intrinsics.Vector256<T>.Equals