diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 2b4b9579282fbc..fc6dd2bd0c423a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1532,7 +1532,7 @@ public static int ILogB(Half x) } Debug.Assert(IsSubnormal(x)); - return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength); + return MinExponent - (ushort.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength); } return x.Exponent; diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs index 9cb4fb9e09da08..545b9a62091637 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -48,8 +48,8 @@ public readonly struct BFloat16 internal const sbyte MinExponent = -126; internal const sbyte MaxExponent = +127; - internal const ushort MinTrailingSignificand = 0x0000; - internal const ushort MaxTrailingSignificand = 0x007F; + internal const byte MinTrailingSignificand = 0x00; + internal const byte MaxTrailingSignificand = 0x7F; internal const int TrailingSignificandLength = 7; internal const int SignificandLength = TrailingSignificandLength + 1; @@ -124,7 +124,7 @@ internal byte Significand } } - internal ushort TrailingSignificand + internal byte TrailingSignificand { get { @@ -138,9 +138,9 @@ internal static byte ExtractBiasedExponentFromBits(ushort bits) return (byte)((bits >> BiasedExponentShift) & ShiftedBiasedExponentMask); } - internal static ushort ExtractTrailingSignificandFromBits(ushort bits) + internal static byte ExtractTrailingSignificandFromBits(ushort bits) { - return (ushort)(bits & TrailingSignificandMask); + return (byte)(bits & TrailingSignificandMask); } // INumberBase @@ -877,12 +877,12 @@ public static bool IsPow2(BFloat16 value) } byte biasedExponent = ExtractBiasedExponentFromBits(bits); - ushort trailingSignificand = ExtractTrailingSignificandFromBits(bits); + byte trailingSignificand = ExtractTrailingSignificandFromBits(bits); if (biasedExponent == MinBiasedExponent) { // Subnormal values have 1 bit set when they're powers of 2 - return ushort.PopCount(trailingSignificand) == 1; + return byte.PopCount(trailingSignificand) == 1; } else if (biasedExponent == MaxBiasedExponent) { @@ -1191,7 +1191,7 @@ public static int ILogB(BFloat16 x) } Debug.Assert(IsSubnormal(x)); - return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength); + return MinExponent - byte.LeadingZeroCount(x.TrailingSignificand); } return x.Exponent; 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 4127a0321d3b6e..62a8d831e9fccd 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 @@ -2244,5 +2244,30 @@ public static void RadiansToDegreesTest(Half value, Half expectedResult, Half al AssertExtensions.Equal(-expectedResult, Half.RadiansToDegrees(-value), allowedVariance); AssertExtensions.Equal(+expectedResult, Half.RadiansToDegrees(+value), allowedVariance); } + + [Theory] + [InlineData(float.PositiveInfinity, int.MaxValue)] + [InlineData(float.NaN, int.MaxValue)] + [InlineData(0.0f, int.MinValue)] + [InlineData(1.0f, 0)] + [InlineData(2.0f, 1)] + [InlineData(4.0f, 2)] + [InlineData(0.5f, -1)] + public static void ILogB(float value, int expectedResult) + { + Assert.Equal(expectedResult, Half.ILogB((Half)value)); + } + + [Fact] + public static void ILogB_Subnormal() + { + // Half.Epsilon is the smallest positive subnormal value + // Its ILogB should be -24 (floor(log2(5.9604645E-08))) + Assert.Equal(-24, Half.ILogB(Half.Epsilon)); + + // Test another subnormal value: 0x0200 (half of max subnormal) + Half subnormal = BitConverter.UInt16BitsToHalf(0x0200); + Assert.Equal(-15, Half.ILogB(subnormal)); + } } } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs index c4e3e40c3adce7..08597497d80b3a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs @@ -2271,6 +2271,31 @@ public static void RadiansToDegreesTest(BFloat16 value, BFloat16 expectedResult, AssertEqual(+expectedResult, BFloat16.RadiansToDegrees(+value), allowedVariance); } + [Theory] + [InlineData(float.PositiveInfinity, int.MaxValue)] + [InlineData(float.NaN, int.MaxValue)] + [InlineData(0.0f, int.MinValue)] + [InlineData(1.0f, 0)] + [InlineData(2.0f, 1)] + [InlineData(4.0f, 2)] + [InlineData(0.5f, -1)] + public static void ILogB(float value, int expectedResult) + { + Assert.Equal(expectedResult, BFloat16.ILogB((BFloat16)value)); + } + + [Fact] + public static void ILogB_Subnormal() + { + // BFloat16.Epsilon is the smallest positive subnormal value + // Its ILogB should be -133 + Assert.Equal(-133, BFloat16.ILogB(BFloat16.Epsilon)); + + // Test another subnormal value: 0x0040 (half of max subnormal) + BFloat16 subnormal = BitConverter.UInt16BitsToBFloat16(0x0040); + Assert.Equal(-127, BFloat16.ILogB(subnormal)); + } + public static IEnumerable TryWriteSignificandBigEndianTest_TestData() => [ [BFloat16.NegativeInfinity, 1, new byte[] { 0x80 }],