diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs
index a07ea3706070aa..40b2587b806b09 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Half.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs
@@ -8,6 +8,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics.X86;
namespace System
{
@@ -157,6 +158,12 @@ internal static ushort ExtractTrailingSignificandFromBits(ushort bits)
///
public static bool operator <(Half left, Half right)
{
+ if (Avx2.IsSupported)
+ {
+ // (float)Half lowers to a hardware conversion here, so comparing as float is cheaper.
+ return (float)left < (float)right;
+ }
+
if (IsNaN(left) || IsNaN(right))
{
// IEEE defines that NaN is unordered with respect to everything, including itself.
@@ -185,6 +192,12 @@ internal static ushort ExtractTrailingSignificandFromBits(ushort bits)
///
public static bool operator <=(Half left, Half right)
{
+ if (Avx2.IsSupported)
+ {
+ // (float)Half lowers to a hardware conversion here, so comparing as float is cheaper.
+ return (float)left <= (float)right;
+ }
+
if (IsNaN(left) || IsNaN(right))
{
// IEEE defines that NaN is unordered with respect to everything, including itself.
@@ -437,28 +450,31 @@ public int CompareTo(object? obj)
/// A value less than zero if this is less than , zero if this is equal to , or a value greater than zero if this is greater than .
public int CompareTo(Half other)
{
- if (this < other)
+ if (Avx2.IsSupported)
{
- return -1;
+ // (float)Half lowers to a hardware conversion here, so comparing as float is cheaper.
+ return ((float)this).CompareTo((float)other);
}
- if (this > other)
+ if (IsNaN(this))
{
- return 1;
+ return IsNaN(other) ? 0 : -1;
}
- if (this == other)
+ if (IsNaN(other))
{
- return 0;
+ return 1;
}
- if (IsNaN(this))
- {
- return IsNaN(other) ? 0 : -1;
- }
+ // Neither value is NaN, so map the sign-magnitude bits to a monotonic ordering.
+ return GetCompareKey(_value) - GetCompareKey(other._value);
+ }
- Debug.Assert(IsNaN(other));
- return 1;
+ private static int GetCompareKey(ushort bits)
+ {
+ // Positive maps to 0x8000 + bits and negative maps to 0x8000 - magnitude, so both zeros
+ // collapse to 0x8000 while the ordering stays monotonic across the finite and infinite range.
+ return ((bits & SignMask) == 0) ? (SignMask + bits) : (SignMask - (bits & ~SignMask));
}
///
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs
index ee6f0fbbde659e..aa8422565ae2c7 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs
@@ -341,6 +341,12 @@ public static IEnumerable