Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/coreclr/jit/simdashwintrinsiclistarm64.h

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions src/coreclr/jit/simdashwintrinsiclistxarch.h

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,20 @@ private void TestEqualsVector<T>() where T : struct, INumber<T>
Assert.False(Vector<T>.Zero.Equals(Vector<T>.One));
Assert.False(Vector<T>.Zero.Equals(new Vector<T>(Util.One<T>())));
}

[Fact]
public void VectorDoubleEqualsNaNTest()
{
var nan = new Vector<double>(double.NaN);
Assert.True(nan.Equals(nan));
}

[Fact]
public void VectorSingleEqualsNaNTest()
{
var nan = new Vector<float>(float.NaN);
Assert.True(nan.Equals(nan));
}
#endregion

#region System.Object Overloads
Expand Down
15 changes: 7 additions & 8 deletions src/libraries/System.Numerics.Vectors/tests/Matrix3x2Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ public void Matrix3x2IsIdentityTest()

// A test for Matrix3x2 comparison involving NaN values
[Fact]
public void Matrix3x2EqualsNanTest()
public void Matrix3x2EqualsNaNTest()
{
Matrix3x2 a = new Matrix3x2(float.NaN, 0, 0, 0, 0, 0);
Matrix3x2 b = new Matrix3x2(0, float.NaN, 0, 0, 0, 0);
Expand Down Expand Up @@ -1020,13 +1020,12 @@ public void Matrix3x2EqualsNanTest()
Assert.False(e.IsIdentity);
Assert.False(f.IsIdentity);

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
Assert.False(e.Equals(e));
Assert.False(f.Equals(f));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
Assert.True(c.Equals(c));
Assert.True(d.Equals(d));
Assert.True(e.Equals(e));
Assert.True(f.Equals(f));
}

// A test to make sure these types are blittable directly into GPU buffer memory layouts
Expand Down
35 changes: 17 additions & 18 deletions src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2490,7 +2490,7 @@ public void Matrix4x4From3x2Test()

// A test for Matrix4x4 comparison involving NaN values
[Fact]
public void Matrix4x4EqualsNanTest()
public void Matrix4x4EqualsNaNTest()
{
Matrix4x4 a = new Matrix4x4(float.NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Matrix4x4 b = new Matrix4x4(0, float.NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Expand Down Expand Up @@ -2577,23 +2577,22 @@ public void Matrix4x4EqualsNanTest()
Assert.False(o.IsIdentity);
Assert.False(p.IsIdentity);

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
Assert.False(e.Equals(e));
Assert.False(f.Equals(f));
Assert.False(g.Equals(g));
Assert.False(h.Equals(h));
Assert.False(i.Equals(i));
Assert.False(j.Equals(j));
Assert.False(k.Equals(k));
Assert.False(l.Equals(l));
Assert.False(m.Equals(m));
Assert.False(n.Equals(n));
Assert.False(o.Equals(o));
Assert.False(p.Equals(p));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
Assert.True(c.Equals(c));
Assert.True(d.Equals(d));
Assert.True(e.Equals(e));
Assert.True(f.Equals(f));
Assert.True(g.Equals(g));
Assert.True(h.Equals(h));
Assert.True(i.Equals(i));
Assert.True(j.Equals(j));
Assert.True(k.Equals(k));
Assert.True(l.Equals(l));
Assert.True(m.Equals(m));
Assert.True(n.Equals(n));
Assert.True(o.Equals(o));
Assert.True(p.Equals(p));
}

// A test to make sure these types are blittable directly into GPU buffer memory layouts
Expand Down
13 changes: 6 additions & 7 deletions src/libraries/System.Numerics.Vectors/tests/PlaneTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void PlaneGetHashCodeTest()
{
Plane target = new Plane(1.0f, 2.0f, 3.0f, 4.0f);

int expected = target.Normal.GetHashCode() + target.D.GetHashCode();
int expected = HashCode.Combine(target.Normal, target.D);
int actual = target.GetHashCode();
Assert.Equal(expected, actual);
}
Expand Down Expand Up @@ -286,7 +286,7 @@ public void PlaneTransformTest2()

// A test for Plane comparison involving NaN values
[Fact]
public void PlaneEqualsNanTest()
public void PlaneEqualsNaNTest()
{
Plane a = new Plane(float.NaN, 0, 0, 0);
Plane b = new Plane(0, float.NaN, 0, 0);
Expand All @@ -308,11 +308,10 @@ public void PlaneEqualsNanTest()
Assert.False(c.Equals(new Plane(0, 0, 0, 0)));
Assert.False(d.Equals(new Plane(0, 0, 0, 0)));

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
Assert.True(c.Equals(c));
Assert.True(d.Equals(d));
}

/* Enable when size of Vector3 is correct
Expand Down
13 changes: 6 additions & 7 deletions src/libraries/System.Numerics.Vectors/tests/QuaternionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ public void QuaternionGetHashCodeTest()
{
Quaternion a = new Quaternion(1.0f, 2.0f, 3.0f, 4.0f);

int expected = unchecked(a.X.GetHashCode() + a.Y.GetHashCode() + a.Z.GetHashCode() + a.W.GetHashCode());
int expected = HashCode.Combine(a.X, a.Y, a.Z, a.W);
int actual = a.GetHashCode();
Assert.Equal(expected, actual);
}
Expand Down Expand Up @@ -949,7 +949,7 @@ public void QuaternionIsIdentityTest()

// A test for Quaternion comparison involving NaN values
[Fact]
public void QuaternionEqualsNanTest()
public void QuaternionEqualsNaNTest()
{
Quaternion a = new Quaternion(float.NaN, 0, 0, 0);
Quaternion b = new Quaternion(0, float.NaN, 0, 0);
Expand All @@ -976,11 +976,10 @@ public void QuaternionEqualsNanTest()
Assert.False(c.IsIdentity);
Assert.False(d.IsIdentity);

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
Assert.True(c.Equals(c));
Assert.True(d.Equals(d));
}

// A test to make sure these types are blittable directly into GPU buffer memory layouts
Expand Down
7 changes: 3 additions & 4 deletions src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ public void Vector2EqualsTest1()

// A test for Vector2f comparison involving NaN values
[Fact]
public void Vector2EqualsNanTest()
public void Vector2EqualsNaNTest()
{
Vector2 a = new Vector2(float.NaN, 0);
Vector2 b = new Vector2(0, float.NaN);
Expand All @@ -1147,9 +1147,8 @@ public void Vector2EqualsNanTest()
Assert.False(a.Equals(Vector2.Zero));
Assert.False(b.Equals(Vector2.Zero));

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
}

// A test for Reflect (Vector2f, Vector2f)
Expand Down
9 changes: 4 additions & 5 deletions src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,7 @@ public void Vector3ConstructorTest5()

// A test for Vector3f comparison involving NaN values
[Fact]
public void Vector3EqualsNanTest()
public void Vector3EqualsNaNTest()
{
Vector3 a = new Vector3(float.NaN, 0, 0);
Vector3 b = new Vector3(0, float.NaN, 0);
Expand All @@ -1234,10 +1234,9 @@ public void Vector3EqualsNanTest()
Assert.False(b.Equals(Vector3.Zero));
Assert.False(c.Equals(Vector3.Zero));

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
Assert.True(c.Equals(c));
}

[Fact]
Expand Down
11 changes: 5 additions & 6 deletions src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,7 +1441,7 @@ public void Vector4ConstructorTest6()

// A test for Vector4f comparison involving NaN values
[Fact]
public void Vector4EqualsNanTest()
public void Vector4EqualsNaNTest()
{
Vector4 a = new Vector4(float.NaN, 0, 0, 0);
Vector4 b = new Vector4(0, float.NaN, 0, 0);
Expand All @@ -1463,11 +1463,10 @@ public void Vector4EqualsNanTest()
Assert.False(c.Equals(Vector4.Zero));
Assert.False(d.Equals(Vector4.Zero));

// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
Assert.True(a.Equals(a));
Assert.True(b.Equals(b));
Assert.True(c.Equals(c));
Assert.True(d.Equals(d));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;

namespace System.Numerics
{
Expand Down Expand Up @@ -633,9 +634,30 @@ public override readonly bool Equals([NotNullWhen(true)] object? obj)
/// <param name="other">The other matrix.</param>
/// <returns><see langword="true" /> if the two matrices are equal; otherwise, <see langword="false" />.</returns>
/// <remarks>Two matrices are equal if all their corresponding elements are equal.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Matrix3x2 other)
{
return this == other;
// This function needs to account for floating-point equality around NaN
// and so must behave equivalently to the underlying float/double.Equals

if (Vector128.IsHardwareAccelerated)
{
// We'll two two overlapping comparisons. The first gets M11, M12, M21, and M22
// The second will get M21, M22, M31, and M32. This is more efficient overall.

return Vector128.LoadUnsafe(ref Unsafe.AsRef(in M11)).Equals(Vector128.LoadUnsafe(ref other.M11))
&& Vector128.LoadUnsafe(ref Unsafe.AsRef(in M21)).Equals(Vector128.LoadUnsafe(ref other.M21));

}

return SoftwareFallback(in this, other);

static bool SoftwareFallback(in Matrix3x2 self, Matrix3x2 other)
{
return self.M11.Equals(other.M11) && self.M22.Equals(other.M22) // Check diagonal element first for early out.
&& self.M12.Equals(other.M12) && self.M21.Equals(other.M21)
&& self.M31.Equals(other.M31) && self.M32.Equals(other.M32);
}
}

/// <summary>Calculates the determinant for this matrix.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2189,9 +2189,30 @@ public override readonly bool Equals([NotNullWhen(true)] object? obj)
/// <summary>Returns a value that indicates whether this instance and another 4x4 matrix are equal.</summary>
/// <param name="other">The other matrix.</param>
/// <returns><see langword="true" /> if the two matrices are equal; otherwise, <see langword="false" />.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Matrix4x4 other)
{
return this == other;
// This function needs to account for floating-point equality around NaN
// and so must behave equivalently to the underlying float/double.Equals

if (Vector128.IsHardwareAccelerated)
{
return Vector128.LoadUnsafe(ref Unsafe.AsRef(in M11)).Equals(Vector128.LoadUnsafe(ref other.M11))
&& Vector128.LoadUnsafe(ref Unsafe.AsRef(in M21)).Equals(Vector128.LoadUnsafe(ref other.M21))
&& Vector128.LoadUnsafe(ref Unsafe.AsRef(in M31)).Equals(Vector128.LoadUnsafe(ref other.M31))
&& Vector128.LoadUnsafe(ref Unsafe.AsRef(in M41)).Equals(Vector128.LoadUnsafe(ref other.M41));

}

return SoftwareFallback(in this, other);

static bool SoftwareFallback(in Matrix4x4 self, Matrix4x4 other)
{
return self.M11.Equals(other.M11) && self.M22.Equals(other.M22) && self.M33.Equals(other.M33) && self.M44.Equals(other.M44) // Check diagonal element first for early out.
&& self.M12.Equals(other.M12) && self.M13.Equals(other.M13) && self.M14.Equals(other.M14) && self.M21.Equals(other.M21)
&& self.M23.Equals(other.M23) && self.M24.Equals(other.M24) && self.M31.Equals(other.M31) && self.M32.Equals(other.M32)
&& self.M34.Equals(other.M34) && self.M41.Equals(other.M41) && self.M42.Equals(other.M42) && self.M43.Equals(other.M43);
}
}

/// <summary>Calculates the determinant of the current 4x4 matrix.</summary>
Expand Down
21 changes: 13 additions & 8 deletions src/libraries/System.Private.CoreLib/src/System/Numerics/Plane.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;

namespace System.Numerics
{
Expand Down Expand Up @@ -298,24 +299,28 @@ public override readonly bool Equals([NotNullWhen(true)] object? obj)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Plane other)
{
if (Vector.IsHardwareAccelerated)
// This function needs to account for floating-point equality around NaN
// and so must behave equivalently to the underlying float/double.Equals

if (Vector128.IsHardwareAccelerated)
{
return Normal.Equals(other.Normal) && D == other.D;
return Vector128.LoadUnsafe(ref Unsafe.AsRef(in Normal.X)).Equals(Vector128.LoadUnsafe(ref other.Normal.X));
}
else

return SoftwareFallback(in this, other);

static bool SoftwareFallback(in Plane self, Plane other)
{
return (Normal.X == other.Normal.X &&
Normal.Y == other.Normal.Y &&
Normal.Z == other.Normal.Z &&
D == other.D);
return self.Normal.Equals(other.Normal)
&& self.D.Equals(other.D);
}
}

/// <summary>Returns the hash code for this instance.</summary>
/// <returns>The hash code.</returns>
public override readonly int GetHashCode()
{
return Normal.GetHashCode() + D.GetHashCode();
return HashCode.Combine(Normal, D);
}

/// <summary>Returns the string representation of this plane object.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;

namespace System.Numerics
{
Expand Down Expand Up @@ -668,16 +669,33 @@ public override readonly bool Equals([NotNullWhen(true)] object? obj)
/// <param name="other">The other quaternion.</param>
/// <returns><see langword="true" /> if the two quaternions are equal; otherwise, <see langword="false" />.</returns>
/// <remarks>Two quaternions are equal if each of their corresponding components is equal.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Quaternion other)
{
return this == other;
// This function needs to account for floating-point equality around NaN
// and so must behave equivalently to the underlying float/double.Equals

if (Vector128.IsHardwareAccelerated)
{
return Vector128.LoadUnsafe(ref Unsafe.AsRef(in X)).Equals(Vector128.LoadUnsafe(ref other.X));
}

return SoftwareFallback(in this, other);

static bool SoftwareFallback(in Quaternion self, Quaternion other)
{
return self.X.Equals(other.X)
&& self.Y.Equals(other.Y)
&& self.Z.Equals(other.Z)
&& self.W.Equals(other.W);
}
}

/// <summary>Returns the hash code for this instance.</summary>
/// <returns>The hash code.</returns>
public override readonly int GetHashCode()
{
return unchecked(X.GetHashCode() + Y.GetHashCode() + Z.GetHashCode() + W.GetHashCode());
return HashCode.Combine(X, Y, Z, W);
}

/// <summary>Calculates the length of the quaternion.</summary>
Expand Down
Loading