From 589afe066a57bd64c54ace0b12a2dcb40858d45f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 22:56:42 +0800 Subject: [PATCH 01/67] Add api for BFloat16 --- .../System.Private.CoreLib.Shared.projitems | 1 + .../src/System/Numerics/BFloat16.cs | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index a73e8247a58e72..adb9620e6f49f1 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -587,6 +587,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs new file mode 100644 index 00000000000000..c3c14085b2a4fb --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Numerics +{ + public readonly struct BFloat16 + : IComparable, + IComparable, + IEquatable + { + public static BFloat16 Epsilon { get; } + public static BFloat16 MinValue { get; } + public static BFloat16 MaxValue { get; } + + // Casting + public static explicit operator BFloat16(float value); + public static explicit operator BFloat16(double value); + public static explicit operator float(BFloat16 value); + public static explicit operator double(BFloat16 value); + + // Comparison + public int CompareTo(object value); + public int CompareTo(BFloat16 value); + public static bool operator ==(BFloat16 left, BFloat16 right); + public static bool operator !=(BFloat16 left, BFloat16 right); + public static bool operator <(BFloat16 left, BFloat16 right); + public static bool operator >(BFloat16 left, BFloat16 right); + public static bool operator <=(BFloat16 left, BFloat16 right); + public static bool operator >=(BFloat16 left, BFloat16 right); + + // Equality + public bool Equals(BFloat16 obj); + public override bool Equals(object? obj); + public override int GetHashCode(); + + // ToString override + public override string ToString(); + } +} From 312d05142dcf46a3b5162fabffdf1ff2b4254816 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 23:01:44 +0800 Subject: [PATCH 02/67] Creating --- .../src/System/Numerics/BFloat16.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 c3c14085b2a4fb..9a136cdc4c7e69 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; + namespace System.Numerics { public readonly struct BFloat16 @@ -12,11 +14,15 @@ public readonly struct BFloat16 public static BFloat16 MinValue { get; } public static BFloat16 MaxValue { get; } + internal readonly ushort _value; + + internal BFloat16(ushort value) => _value = value; + // Casting - public static explicit operator BFloat16(float value); - public static explicit operator BFloat16(double value); - public static explicit operator float(BFloat16 value); - public static explicit operator double(BFloat16 value); + public static explicit operator BFloat16(float value) => new BFloat16((ushort)(BitConverter.SingleToUInt32Bits(value) >> 16)); + public static explicit operator BFloat16(double value) => (BFloat16)(float)value; + public static explicit operator float(BFloat16 value) => BitConverter.Int32BitsToSingle(value._value << 16); + public static explicit operator double(BFloat16 value) => (double)(float)value; // Comparison public int CompareTo(object value); From 5e1c98176e662abd484d2070277cc87b70251811 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 23:09:57 +0800 Subject: [PATCH 03/67] Equals and GetHashCode --- .../src/System/Numerics/BFloat16.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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 9a136cdc4c7e69..7cbc88c1b6e816 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Buffers.Binary; - namespace System.Numerics { public readonly struct BFloat16 @@ -35,11 +33,11 @@ public readonly struct BFloat16 public static bool operator >=(BFloat16 left, BFloat16 right); // Equality - public bool Equals(BFloat16 obj); - public override bool Equals(object? obj); - public override int GetHashCode(); + public bool Equals(BFloat16 other) => ((float)this).Equals((float)other); + public override bool Equals(object? obj) => obj is BFloat16 other && Equals(other); + public override int GetHashCode() => ((float)this).GetHashCode(); // ToString override - public override string ToString(); + public override string ToString() => ((float)this).ToString(); } } From 1fb47656060389887ba07980549ce66339dcd600 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 23:17:02 +0800 Subject: [PATCH 04/67] Comparison --- .../src/Resources/Strings.resx | 7 ++++-- .../src/System/Numerics/BFloat16.cs | 23 ++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index b6d8fd00aa4049..f9594228b08ce2 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3346,7 +3346,7 @@ Object type {0} does not match target type {1}. - + Non-static field requires a target. @@ -4310,4 +4310,7 @@ Blocking wait is not supported on the JS interop threads. - + + Object must be of type BFloat16. + + \ No newline at end of file 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 7cbc88c1b6e816..58991935bedeb8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -23,14 +23,21 @@ public readonly struct BFloat16 public static explicit operator double(BFloat16 value) => (double)(float)value; // Comparison - public int CompareTo(object value); - public int CompareTo(BFloat16 value); - public static bool operator ==(BFloat16 left, BFloat16 right); - public static bool operator !=(BFloat16 left, BFloat16 right); - public static bool operator <(BFloat16 left, BFloat16 right); - public static bool operator >(BFloat16 left, BFloat16 right); - public static bool operator <=(BFloat16 left, BFloat16 right); - public static bool operator >=(BFloat16 left, BFloat16 right); + public int CompareTo(object? obj) + { + if (obj is not BFloat16 other) + { + return (obj is null) ? 1 : throw new ArgumentException(SR.Arg_MustBeBFloat16); + } + return CompareTo(other); + } + public int CompareTo(BFloat16 other) => ((float)this).CompareTo((float)other); + public static bool operator ==(BFloat16 left, BFloat16 right) => (float)left == (float)right; + public static bool operator !=(BFloat16 left, BFloat16 right) => (float)left != (float)right; + public static bool operator <(BFloat16 left, BFloat16 right) => (float)left < (float)right; + public static bool operator >(BFloat16 left, BFloat16 right) => (float)left > (float)right; + public static bool operator <=(BFloat16 left, BFloat16 right) => (float)left <= (float)right; + public static bool operator >=(BFloat16 left, BFloat16 right) => (float)left >= (float)right; // Equality public bool Equals(BFloat16 other) => ((float)this).Equals((float)other); From fc05d3b3d34e3aba85a42cfc658853387793d65d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 23:20:36 +0800 Subject: [PATCH 05/67] Constants and comment --- .../src/System/Numerics/BFloat16.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) 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 58991935bedeb8..0a8a8062598a5b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -8,9 +8,14 @@ public readonly struct BFloat16 IComparable, IEquatable { - public static BFloat16 Epsilon { get; } - public static BFloat16 MinValue { get; } - public static BFloat16 MaxValue { get; } + private const ushort EpsilonBits = 0x0001; + + private const ushort MinValueBits = 0xFF7F; + private const ushort MaxValueBits = 0x7F7F; + + public static BFloat16 Epsilon => new BFloat16(EpsilonBits); + public static BFloat16 MinValue => new BFloat16(MinValueBits); + public static BFloat16 MaxValue => new BFloat16(MaxValueBits); internal readonly ushort _value; @@ -22,6 +27,9 @@ public readonly struct BFloat16 public static explicit operator float(BFloat16 value) => BitConverter.Int32BitsToSingle(value._value << 16); public static explicit operator double(BFloat16 value) => (double)(float)value; + // BFloat is effectively a truncation of Single, with lower 16 bits of precision truncated. + // Delegating all operations to Single should be correct and effective. + // Comparison public int CompareTo(object? obj) { From 152fe99db76375c1c1c62c1e0d4166f013752cb0 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 23:31:42 +0800 Subject: [PATCH 06/67] Xml doc --- .../src/System/Numerics/BFloat16.cs | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) 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 0a8a8062598a5b..a73a5b1432037a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -3,6 +3,9 @@ namespace System.Numerics { + /// + /// Represents a shortened (16-bit) version of 32 bit floating-point value (). + /// public readonly struct BFloat16 : IComparable, IComparable, @@ -13,8 +16,19 @@ public readonly struct BFloat16 private const ushort MinValueBits = 0xFF7F; private const ushort MaxValueBits = 0x7F7F; + /// + /// Represents the smallest positive value that is greater than zero. + /// public static BFloat16 Epsilon => new BFloat16(EpsilonBits); + + /// + /// Represents the smallest possible value of . + /// public static BFloat16 MinValue => new BFloat16(MinValueBits); + + /// + /// Represents the largest possible value of . + /// public static BFloat16 MaxValue => new BFloat16(MaxValueBits); internal readonly ushort _value; @@ -22,15 +36,38 @@ public readonly struct BFloat16 internal BFloat16(ushort value) => _value = value; // Casting + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. public static explicit operator BFloat16(float value) => new BFloat16((ushort)(BitConverter.SingleToUInt32Bits(value) >> 16)); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. public static explicit operator BFloat16(double value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator float(BFloat16 value) => BitConverter.Int32BitsToSingle(value._value << 16); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. public static explicit operator double(BFloat16 value) => (double)(float)value; - // BFloat is effectively a truncation of Single, with lower 16 bits of precision truncated. + // BFloat is effectively a truncation of Single, with lower 16 bits of mantissa truncated. // Delegating all operations to Single should be correct and effective. // Comparison + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// 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 . + /// Thrown when is not of type . public int CompareTo(object? obj) { if (obj is not BFloat16 other) @@ -39,20 +76,51 @@ public int CompareTo(object? obj) } return CompareTo(other); } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// 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(BFloat16 other) => ((float)this).CompareTo((float)other); + + /// public static bool operator ==(BFloat16 left, BFloat16 right) => (float)left == (float)right; + + /// public static bool operator !=(BFloat16 left, BFloat16 right) => (float)left != (float)right; + + /// public static bool operator <(BFloat16 left, BFloat16 right) => (float)left < (float)right; + + /// public static bool operator >(BFloat16 left, BFloat16 right) => (float)left > (float)right; + + /// public static bool operator <=(BFloat16 left, BFloat16 right) => (float)left <= (float)right; + + /// public static bool operator >=(BFloat16 left, BFloat16 right) => (float)left >= (float)right; // Equality + + /// + /// Returns a value that indicates whether this instance is equal to a specified value. + /// public bool Equals(BFloat16 other) => ((float)this).Equals((float)other); + + /// + /// Returns a value that indicates whether this instance is equal to a specified . + /// public override bool Equals(object? obj) => obj is BFloat16 other && Equals(other); + + /// + /// Serves as the default hash function. + /// public override int GetHashCode() => ((float)this).GetHashCode(); - // ToString override + /// + /// Returns a string representation of the current value. + /// public override string ToString() => ((float)this).ToString(); } } From 25a16e7dc02043330ee898bcd303b8fdccaea463 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 01:00:31 +0800 Subject: [PATCH 07/67] Using rounding for cast --- .../src/System/Numerics/BFloat16.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) 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 a73a5b1432037a..e31984820e9616 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -40,7 +40,29 @@ public readonly struct BFloat16 /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(float value) => new BFloat16((ushort)(BitConverter.SingleToUInt32Bits(value) >> 16)); + public static explicit operator BFloat16(float value) + { + uint bits = BitConverter.SingleToUInt32Bits(value); + uint upper = bits >> 16; + // Only do rounding for finite numbers + if (float.IsFinite(value)) + { + uint lower = bits & 0xFFFF; + uint sign = upper & 0x8000; + // Strip sign from upper + upper &= 0x7FFF; + // Determine the increment for rounding + // When upper is even, midpoint (0x8000) will tie to no increment, which is effectively a decrement of lower + uint lowerShift = (~upper) & (lower >> 15) & 1; // Upper is even & lower>=0x8000 (not 0) + lower -= lowerShift; + uint increment = lower >> 15; + // Do the increment, MaxValue will be correctly increased to Infinity + upper += increment; + // Put back sign with upper bits and done + upper |= sign; + } + return new BFloat16((ushort)upper); + } /// Explicitly converts a value to its nearest representable value. /// The value to convert. From 50d90aafd5d06e24a7bd8cf09c0b5570560bd225 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 01:14:45 +0800 Subject: [PATCH 08/67] Ref source --- .../System.Runtime/ref/System.Runtime.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 53bba2a3f34973..b68a5d8a64638d 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10590,6 +10590,29 @@ public static void HtmlEncode(string? value, System.IO.TextWriter output) { } } namespace System.Numerics { + public readonly partial struct BFloat16 : System.IComparable, System.IComparable, System.IEquatable + { + private readonly int _dummyPrimitive; + public static System.Numerics.BFloat16 Epsilon { get { throw null; } } + public static System.Numerics.BFloat16 MaxValue { get { throw null; } } + public static System.Numerics.BFloat16 MinValue { get { throw null; } } + public int CompareTo(System.Numerics.BFloat16 other) { throw null; } + public int CompareTo(object? obj) { throw null; } + public bool Equals(System.Numerics.BFloat16 other) { throw null; } + public override bool Equals(object? obj) { throw null; } + public override int GetHashCode() { throw null; } + public static bool operator ==(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static explicit operator System.Numerics.BFloat16 (double value) { throw null; } + public static explicit operator double (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator float (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (float value) { throw null; } + public static bool operator >(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static bool operator >=(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static bool operator !=(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static bool operator <(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static bool operator <=(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public override string ToString() { throw null; } + } public static partial class BitOperations { [System.CLSCompliantAttribute(false)] From 559f2e0f0f2dbba87ca3afde0efdc819a4fbedd0 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 01:24:24 +0800 Subject: [PATCH 09/67] Simple tests --- .../System.Runtime.Tests.csproj | 3 +- .../System/Numerics/BFloat16Tests.cs | 141 ++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj index 6bcf41fe129bd3..29cc2c8786332a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser $(DefineConstants);TARGET_BROWSER @@ -132,6 +132,7 @@ + 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 new file mode 100644 index 00000000000000..ff55b0a951d422 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs @@ -0,0 +1,141 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Xunit; + +namespace System.Numerics.Tests +{ + public class BFloat16Tests + { + private static ushort BFloat16ToUInt16Bits(BFloat16 value) => Unsafe.BitCast(value); + + private static BFloat16 UInt16BitsToBFloat16(ushort value) => Unsafe.BitCast(value); + + private static bool IsNaN(BFloat16 value) => float.IsNaN(BitConverter.Int32BitsToSingle(BFloat16ToUInt16Bits(value) << 16)); + + [Fact] + public static void Epsilon() + { + Assert.Equal(0x0001u, BFloat16ToUInt16Bits(BFloat16.Epsilon)); + } + + [Fact] + public static void MinValue() + { + Assert.Equal(0xFF7Fu, BFloat16ToUInt16Bits(BFloat16.MinValue)); + } + + [Fact] + public static void MaxValue() + { + Assert.Equal(0x7F7Fu, BFloat16ToUInt16Bits(BFloat16.MaxValue)); + } + + [Fact] + public static void Ctor_Empty() + { + var value = new BFloat16(); + Assert.Equal(0x0000, BFloat16ToUInt16Bits(value)); + } + + public static IEnumerable CompareTo_ThrowsArgumentException_TestData() + { + yield return new object[] { "a" }; + yield return new object[] { 234.0 }; + } + + [Theory] + [MemberData(nameof(CompareTo_ThrowsArgumentException_TestData))] + public static void CompareTo_ThrowsArgumentException(object obj) + { + Assert.Throws(() => BFloat16.MaxValue.CompareTo(obj)); + } + + public static IEnumerable CompareTo_TestData() + { + yield return new object[] { Half.MaxValue, Half.MaxValue, 0 }; + yield return new object[] { Half.MaxValue, Half.MinValue, 1 }; + yield return new object[] { Half.Epsilon, BitConverter.UInt16BitsToHalf(0x8001), 1 }; + yield return new object[] { Half.MaxValue, BitConverter.UInt16BitsToHalf(0x0000), 1 }; + yield return new object[] { Half.MaxValue, Half.Epsilon, 1 }; + yield return new object[] { Half.MaxValue, Half.PositiveInfinity, -1 }; + yield return new object[] { Half.MinValue, Half.MaxValue, -1 }; + yield return new object[] { Half.MaxValue, Half.NaN, 1 }; + yield return new object[] { Half.NaN, Half.NaN, 0 }; + yield return new object[] { Half.NaN, BitConverter.UInt16BitsToHalf(0x0000), -1 }; + yield return new object[] { Half.MaxValue, null, 1 }; + yield return new object[] { Half.MinValue, Half.NegativeInfinity, 1 }; + yield return new object[] { Half.NegativeInfinity, Half.MinValue, -1 }; + yield return new object[] { BitConverter.UInt16BitsToHalf(0x8000), Half.NegativeInfinity, 1 }; // Negative zero + yield return new object[] { Half.NegativeInfinity, BitConverter.UInt16BitsToHalf(0x8000), -1 }; // Negative zero + yield return new object[] { Half.NegativeInfinity, Half.NegativeInfinity, 0 }; + yield return new object[] { Half.PositiveInfinity, Half.PositiveInfinity, 0 }; + yield return new object[] { (Half)(-180f), (Half)(-180f), 0 }; + yield return new object[] { (Half)(180f), (Half)(180f), 0 }; + yield return new object[] { (Half)(-180f), (Half)(180f), -1 }; + yield return new object[] { (Half)(180f), (Half)(-180f), 1 }; + yield return new object[] { (Half)(-65535), (object)null, 1 }; + } + + [Theory] + [MemberData(nameof(CompareTo_TestData))] + public static void CompareTo(BFloat16 value, object obj, int expected) + { + if (obj is BFloat16 other) + { + Assert.Equal(expected, Math.Sign(value.CompareTo(other))); + + if (IsNaN(value) || IsNaN(other)) + { + Assert.False(value >= other); + Assert.False(value > other); + Assert.False(value <= other); + Assert.False(value < other); + } + else + { + if (expected >= 0) + { + Assert.True(value >= other); + Assert.False(value < other); + } + if (expected > 0) + { + Assert.True(value > other); + Assert.False(value <= other); + } + if (expected <= 0) + { + Assert.True(value <= other); + Assert.False(value > other); + } + if (expected < 0) + { + Assert.True(value < other); + Assert.False(value >= other); + } + } + } + + Assert.Equal(expected, Math.Sign(value.CompareTo(obj))); + } + + public static IEnumerable Equals_TestData() + { + yield return new object[] { BFloat16.MaxValue, BFloat16.MaxValue, true }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MinValue, false }; + yield return new object[] { BFloat16.MaxValue, UInt16BitsToBFloat16(0x0000), false }; + yield return new object[] { BFloat16.MaxValue, 789.0f, false }; + yield return new object[] { BFloat16.MaxValue, "789", false }; + } + + [Theory] + [MemberData(nameof(Equals_TestData))] + public static void EqualsTest(BFloat16 value, object obj, bool expected) + { + Assert.Equal(expected, value.Equals(obj)); + } + } +} From b24839c8af259e564aae92fde1f872bf343b75ae Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 12:48:47 +0800 Subject: [PATCH 10/67] Conversion tests --- .../System/Numerics/BFloat16Tests.cs | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) 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 ff55b0a951d422..2e83e73ac8bc32 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 @@ -137,5 +137,145 @@ public static void EqualsTest(BFloat16 value, object obj, bool expected) { Assert.Equal(expected, value.Equals(obj)); } + + public static IEnumerable ExplicitConversion_ToSingle_TestData() + { + (BFloat16 Original, float Expected)[] data = // Fraction is truncated for lower 16 bits + { + (UInt16BitsToBFloat16(0b0_01111111_0000000), 1f), // 1 + (UInt16BitsToBFloat16(0b1_01111111_0000000), -1f), // -1 + (BFloat16.MaxValue, BitConverter.UInt32BitsToSingle(0x7F7F0000)), // 3.3895314E+38 + (BFloat16.MinValue, BitConverter.UInt32BitsToSingle(0xFF7F0000)), // -3.3895314E+38 + (UInt16BitsToBFloat16(0b0_01111011_1001100), 0.099609375f), // 0.1ish + (UInt16BitsToBFloat16(0b1_01111011_1001100), -0.099609375f), // -0.1ish + (UInt16BitsToBFloat16(0b0_10000100_0101000), 42f), // 42 + (UInt16BitsToBFloat16(0b1_10000100_0101000), -42f), // -42 + // (BFloat16.PositiveInfinity, float.PositiveInfinity), // PosInfinity + // (BFloat16.NegativeInfinity, float.NegativeInfinity), // NegInfinity + (UInt16BitsToBFloat16(0b0_11111111_1000000), BitConverter.UInt32BitsToSingle(0x7FC00000)), // Positive Quiet NaN + // (BFloat16.NaN, float.NaN), // Negative Quiet NaN + (UInt16BitsToBFloat16(0b0_11111111_1010101), BitConverter.UInt32BitsToSingle(0x7FD50000)), // Positive Signalling NaN - Should preserve payload + (UInt16BitsToBFloat16(0b1_11111111_1010101), BitConverter.UInt32BitsToSingle(0xFFD50000)), // Negative Signalling NaN - Should preserve payload + (BFloat16.Epsilon, BitConverter.UInt32BitsToSingle(0x00010000)), // PosEpsilon = 9.1835E-41 + (UInt16BitsToBFloat16(0), 0), // 0 + (UInt16BitsToBFloat16(0b1_00000000_0000000), -0f), // -0 + (UInt16BitsToBFloat16(0b0_10000000_1001001), 3.140625f), // 3.140625 + (UInt16BitsToBFloat16(0b1_10000000_1001001), -3.140625f), // -3.140625 + (UInt16BitsToBFloat16(0b0_10000000_0101110), 2.71875f), // 2.71875 + (UInt16BitsToBFloat16(0b1_10000000_0101110), -2.71875f), // -2.71875 + (UInt16BitsToBFloat16(0b0_01111111_1000000), 1.5f), // 1.5 + (UInt16BitsToBFloat16(0b1_01111111_1000000), -1.5f), // -1.5 + (UInt16BitsToBFloat16(0b0_01111111_1000001), 1.5078125f), // 1.5078125 + (UInt16BitsToBFloat16(0b1_01111111_1000001), -1.5078125f), // -1.5078125 + (UInt16BitsToBFloat16(0b0_00000001_0000000), BitConverter.UInt32BitsToSingle(0x00800000)), // smallest normal + (UInt16BitsToBFloat16(0b0_00000000_1111111), BitConverter.UInt32BitsToSingle(0x007F0000)), // largest subnormal + (UInt16BitsToBFloat16(0b0_00000000_1000000), BitConverter.UInt32BitsToSingle(0x00400000)), // middle subnormal + (UInt16BitsToBFloat16(0b0_00000000_0111111), BitConverter.UInt32BitsToSingle(0x003F0000)), // just below middle subnormal + (UInt16BitsToBFloat16(0b0_00000000_0000001), BitConverter.UInt32BitsToSingle(0x00010000)), // smallest subnormal + (UInt16BitsToBFloat16(0b1_00000000_0000001), BitConverter.UInt32BitsToSingle(0x80010000)), // highest negative subnormal + (UInt16BitsToBFloat16(0b1_00000000_0111111), BitConverter.UInt32BitsToSingle(0x803F8000)), // just above negative middle subnormal + (UInt16BitsToBFloat16(0b1_00000000_1000000), BitConverter.UInt32BitsToSingle(0x80400000)), // negative middle subnormal + (UInt16BitsToBFloat16(0b1_00000000_1111111), BitConverter.UInt32BitsToSingle(0x807F0000)), // lowest negative subnormal + (UInt16BitsToBFloat16(0b1_00000001_0000000), BitConverter.UInt32BitsToSingle(0x80800000)) // highest negative normal + }; + + foreach ((BFloat16 original, float expected) in data) + { + yield return new object[] { original, expected }; + } + } + + [MemberData(nameof(ExplicitConversion_ToSingle_TestData))] + [Theory] + public static void ExplicitConversion_ToSingle(BFloat16 value, float expected) // Check the underlying bits for verifying NaNs + { + float f = (float)value; + AssertExtensions.Equal(expected, f); + } + public static IEnumerable ExplicitConversion_FromSingle_TestData() + { + (float, BFloat16)[] data = + { + (MathF.PI, UInt16BitsToBFloat16(0b0_10000000_1001001)), // 3.140625 + (MathF.E, UInt16BitsToBFloat16(0b0_10000000_0101110)), // 2.71875 + (-MathF.PI, UInt16BitsToBFloat16(0b1_10000000_1001001)), // -3.140625 + (-MathF.E, UInt16BitsToBFloat16(0b1_10000000_0101110)), // -2.71875 + (float.MaxValue, UInt16BitsToBFloat16(0b0_11111111_0000000)), // Overflow + (float.MinValue, UInt16BitsToBFloat16(0b1_11111111_0000000)), // Overflow + //(float.PositiveInfinity, BFloat16.PositiveInfinity), // Overflow + //(float.NegativeInfinity, BFloat16.NegativeInfinity), // Overflow + //(float.NaN, BFloat16.NaN), // Quiet Negative NaN + (BitConverter.UInt32BitsToSingle(0x7FC00000), UInt16BitsToBFloat16(0b0_11111111_1000000)), // Quiet Positive NaN + (BitConverter.UInt32BitsToSingle(0xFFD55555), UInt16BitsToBFloat16(0b1_11111111_1010101)), // Signalling Negative NaN + (BitConverter.UInt32BitsToSingle(0x7FD55555), UInt16BitsToBFloat16(0b0_11111111_1010101)), // Signalling Positive NaN + (float.Epsilon, UInt16BitsToBFloat16(0)), // Underflow + (-float.Epsilon, UInt16BitsToBFloat16(0b1_00000000_0000000)), // Underflow + (1f, UInt16BitsToBFloat16(0b0_01111111_0000000)), // 1 + (-1f, UInt16BitsToBFloat16(0b1_01111111_0000000)), // -1 + (0f, UInt16BitsToBFloat16(0)), // 0 + (-0f, UInt16BitsToBFloat16(0b1_00000000_0000000)), // -0 + (42f, UInt16BitsToBFloat16(0b0_10000100_0101000)), // 42 + (-42f, UInt16BitsToBFloat16(0b1_10000100_0101000)), // -42 + (0.1f, UInt16BitsToBFloat16(0b0_01111011_1001100)), // 0.0999755859375 + (-0.1f, UInt16BitsToBFloat16(0b1_01111011_1001100)), // -0.0999755859375 + (1.5f, UInt16BitsToBFloat16(0b0_01111111_1000000)), // 1.5 + (-1.5f, UInt16BitsToBFloat16(0b1_01111111_1000000)), // -1.5 + (1.5078125f, UInt16BitsToBFloat16(0b0_01111111_1000001)), // 1.5078125 + (-1.5078125f, UInt16BitsToBFloat16(0b1_01111111_1000001)), // -1.5078125 + (BitConverter.UInt32BitsToSingle(0x00800000), UInt16BitsToBFloat16(0b0_00000001_0000000)), // smallest normal + (BitConverter.UInt32BitsToSingle(0x007F0000), UInt16BitsToBFloat16(0b0_00000000_1111111)), // largest subnormal + (BitConverter.UInt32BitsToSingle(0x00400000), UInt16BitsToBFloat16(0b0_00000000_1000000)), // middle subnormal + (BitConverter.UInt32BitsToSingle(0x003F8000), UInt16BitsToBFloat16(0b0_00000000_0111111)), // just below middle subnormal + (BitConverter.UInt32BitsToSingle(0x00010000), UInt16BitsToBFloat16(0b0_00000000_0000001)), // smallest subnormal + (BitConverter.UInt32BitsToSingle(0x80010000), UInt16BitsToBFloat16(0b1_00000000_0000001)), // highest negative subnormal + (BitConverter.UInt32BitsToSingle(0x803F0000), UInt16BitsToBFloat16(0b1_00000000_0111111)), // just above negative middle subnormal + (BitConverter.UInt32BitsToSingle(0x80400000), UInt16BitsToBFloat16(0b1_00000000_1000000)), // negative middle subnormal + (BitConverter.UInt32BitsToSingle(0x807F0000), UInt16BitsToBFloat16(0b1_00000000_1111111)), // lowest negative subnormal + (BitConverter.UInt32BitsToSingle(0x80800000), UInt16BitsToBFloat16(0b1_00000001_0000000)), // highest negative normal + (BitConverter.UInt32BitsToSingle(0b0_10001001_00000111000000000000001), + UInt16BitsToBFloat16(0b0_10001001_0000100)), // 1052+ULP rounds up + (BitConverter.UInt32BitsToSingle(0b0_10001001_00000111000000000000000), + UInt16BitsToBFloat16(0b0_10001001_0000100)), // 1052 rounds to even + (BitConverter.UInt32BitsToSingle(0b0_10001001_00000110111111111111111), + UInt16BitsToBFloat16(0b0_10001001_0000011)), // 1052-ULP rounds down + (BitConverter.UInt32BitsToSingle(0b0_10001001_00000101000000000000000), + UInt16BitsToBFloat16(0b0_10001001_0000010)), // 1044 rounds to even + (BitConverter.UInt32BitsToSingle(0b1_10001001_00000110111111111111111), + UInt16BitsToBFloat16(0b1_10001001_0000011)), // -1052+ULP rounds towards zero + (BitConverter.UInt32BitsToSingle(0b1_10001001_00000111000000000000000), + UInt16BitsToBFloat16(0b1_10001001_0000100)), // -1052 rounds to even + (BitConverter.UInt32BitsToSingle(0b1_10001001_00000111000000000000001), + UInt16BitsToBFloat16(0b1_10001001_0000100)), // -1052-ULP rounds away from zero + (BitConverter.UInt32BitsToSingle(0b1_10001001_00000101000000000000000), + UInt16BitsToBFloat16(0b1_10001001_0000010)), // -1044 rounds to even + (BitConverter.UInt32BitsToSingle(0b0_00000000_10000111000000000000001), + UInt16BitsToBFloat16(0b0_00000000_1000100)), // subnormal + ULP rounds up + (BitConverter.UInt32BitsToSingle(0b0_00000000_10000111000000000000000), + UInt16BitsToBFloat16(0b0_00000000_1000100)), // subnormal rounds to even + (BitConverter.UInt32BitsToSingle(0b0_00000000_10000110111111111111111), + UInt16BitsToBFloat16(0b0_00000000_1000011)), // subnormal - ULP rounds down + (BitConverter.UInt32BitsToSingle(0b1_00000000_10000110111111111111111), + UInt16BitsToBFloat16(0b1_00000000_1000011)), // neg subnormal + ULP rounds higher + (BitConverter.UInt32BitsToSingle(0b1_00000000_10000111000000000000000), + UInt16BitsToBFloat16(0b1_00000000_1000100)), // neg subnormal rounds to even + (BitConverter.UInt32BitsToSingle(0b1_00000000_10000111000000000000001), + UInt16BitsToBFloat16(0b1_00000000_1000100)), // neg subnormal - ULP rounds lower, + (BitConverter.UInt32BitsToSingle(0b0_00000000_00000000110000000000000), + UInt16BitsToBFloat16(0b0_00000_000000000)), // (BFloat16-precision minimum subnormal / 2) should underflow to zero + }; + + foreach ((float original, BFloat16 expected) in data) + { + yield return new object[] { original, expected }; + } + } + + [MemberData(nameof(ExplicitConversion_FromSingle_TestData))] + [Theory] + public static void ExplicitConversion_FromSingle(float f, BFloat16 expected) // Check the underlying bits for verifying NaNs + { + BFloat16 b16 = (BFloat16)f; + AssertExtensions.Equal(BFloat16ToUInt16Bits(expected), BFloat16ToUInt16Bits(b16)); + } } } From 8284526d6256534e17265833d9891114dd6ff95e Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 13:31:33 +0800 Subject: [PATCH 11/67] Stripping sign is redundant --- .../System.Private.CoreLib/src/System/Numerics/BFloat16.cs | 5 ----- 1 file changed, 5 deletions(-) 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 e31984820e9616..368c5232be80d2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -48,9 +48,6 @@ public static explicit operator BFloat16(float value) if (float.IsFinite(value)) { uint lower = bits & 0xFFFF; - uint sign = upper & 0x8000; - // Strip sign from upper - upper &= 0x7FFF; // Determine the increment for rounding // When upper is even, midpoint (0x8000) will tie to no increment, which is effectively a decrement of lower uint lowerShift = (~upper) & (lower >> 15) & 1; // Upper is even & lower>=0x8000 (not 0) @@ -58,8 +55,6 @@ public static explicit operator BFloat16(float value) uint increment = lower >> 15; // Do the increment, MaxValue will be correctly increased to Infinity upper += increment; - // Put back sign with upper bits and done - upper |= sign; } return new BFloat16((ushort)upper); } From 8e32e718f5508735f84a95d0d5876136ed9ff975 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 18:25:05 +0800 Subject: [PATCH 12/67] Fix test copied from Half --- .../System/Numerics/BFloat16Tests.cs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) 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 2e83e73ac8bc32..53eda2a785cc62 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 @@ -55,28 +55,28 @@ public static void CompareTo_ThrowsArgumentException(object obj) public static IEnumerable CompareTo_TestData() { - yield return new object[] { Half.MaxValue, Half.MaxValue, 0 }; - yield return new object[] { Half.MaxValue, Half.MinValue, 1 }; - yield return new object[] { Half.Epsilon, BitConverter.UInt16BitsToHalf(0x8001), 1 }; - yield return new object[] { Half.MaxValue, BitConverter.UInt16BitsToHalf(0x0000), 1 }; - yield return new object[] { Half.MaxValue, Half.Epsilon, 1 }; - yield return new object[] { Half.MaxValue, Half.PositiveInfinity, -1 }; - yield return new object[] { Half.MinValue, Half.MaxValue, -1 }; - yield return new object[] { Half.MaxValue, Half.NaN, 1 }; - yield return new object[] { Half.NaN, Half.NaN, 0 }; - yield return new object[] { Half.NaN, BitConverter.UInt16BitsToHalf(0x0000), -1 }; - yield return new object[] { Half.MaxValue, null, 1 }; - yield return new object[] { Half.MinValue, Half.NegativeInfinity, 1 }; - yield return new object[] { Half.NegativeInfinity, Half.MinValue, -1 }; - yield return new object[] { BitConverter.UInt16BitsToHalf(0x8000), Half.NegativeInfinity, 1 }; // Negative zero - yield return new object[] { Half.NegativeInfinity, BitConverter.UInt16BitsToHalf(0x8000), -1 }; // Negative zero - yield return new object[] { Half.NegativeInfinity, Half.NegativeInfinity, 0 }; - yield return new object[] { Half.PositiveInfinity, Half.PositiveInfinity, 0 }; - yield return new object[] { (Half)(-180f), (Half)(-180f), 0 }; - yield return new object[] { (Half)(180f), (Half)(180f), 0 }; - yield return new object[] { (Half)(-180f), (Half)(180f), -1 }; - yield return new object[] { (Half)(180f), (Half)(-180f), 1 }; - yield return new object[] { (Half)(-65535), (object)null, 1 }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MaxValue, 0 }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MinValue, 1 }; + yield return new object[] { BFloat16.Epsilon, UInt16BitsToBFloat16(0x8001), 1 }; + yield return new object[] { BFloat16.MaxValue, UInt16BitsToBFloat16(0x0000), 1 }; + yield return new object[] { BFloat16.MaxValue, BFloat16.Epsilon, 1 }; + // yield return new object[] { BFloat16.MaxValue, BFloat16.PositiveInfinity, -1 }; + yield return new object[] { BFloat16.MinValue, BFloat16.MaxValue, -1 }; + // yield return new object[] { BFloat16.MaxValue, BFloat16.NaN, 1 }; + // yield return new object[] { BFloat16.NaN, BFloat16.NaN, 0 }; + // yield return new object[] { BFloat16.NaN, UInt16BitsToBFloat16(0x0000), -1 }; + yield return new object[] { BFloat16.MaxValue, null, 1 }; + // yield return new object[] { BFloat16.MinValue, BFloat16.NegativeInfinity, 1 }; + // yield return new object[] { BFloat16.NegativeInfinity, BFloat16.MinValue, -1 }; + // yield return new object[] { UInt16BitsToBFloat16(0x8000), BFloat16.NegativeInfinity, 1 }; // Negative zero + // yield return new object[] { BFloat16.NegativeInfinity, UInt16BitsToBFloat16(0x8000), -1 }; // Negative zero + // yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NegativeInfinity, 0 }; + // yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0 }; + yield return new object[] { (BFloat16)(-180f), (BFloat16)(-180f), 0 }; + yield return new object[] { (BFloat16)(180f), (BFloat16)(180f), 0 }; + yield return new object[] { (BFloat16)(-180f), (BFloat16)(180f), -1 }; + yield return new object[] { (BFloat16)(180f), (BFloat16)(-180f), 1 }; + yield return new object[] { (BFloat16)(-65535), (object)null, 1 }; } [Theory] From 4bd266e8372a660dcccb025107605aa4ee283649 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Feb 2024 18:34:03 +0800 Subject: [PATCH 13/67] Fix conversion test cases --- .../System/Numerics/BFloat16Tests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 53eda2a785cc62..1c4811807134d9 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 @@ -146,8 +146,8 @@ public static IEnumerable ExplicitConversion_ToSingle_TestData() (UInt16BitsToBFloat16(0b1_01111111_0000000), -1f), // -1 (BFloat16.MaxValue, BitConverter.UInt32BitsToSingle(0x7F7F0000)), // 3.3895314E+38 (BFloat16.MinValue, BitConverter.UInt32BitsToSingle(0xFF7F0000)), // -3.3895314E+38 - (UInt16BitsToBFloat16(0b0_01111011_1001100), 0.099609375f), // 0.1ish - (UInt16BitsToBFloat16(0b1_01111011_1001100), -0.099609375f), // -0.1ish + (UInt16BitsToBFloat16(0b0_01111011_1001101), 0.10009765625f), // 0.1ish + (UInt16BitsToBFloat16(0b1_01111011_1001101), -0.10009765625f), // -0.1ish (UInt16BitsToBFloat16(0b0_10000100_0101000), 42f), // 42 (UInt16BitsToBFloat16(0b1_10000100_0101000), -42f), // -42 // (BFloat16.PositiveInfinity, float.PositiveInfinity), // PosInfinity @@ -173,7 +173,7 @@ public static IEnumerable ExplicitConversion_ToSingle_TestData() (UInt16BitsToBFloat16(0b0_00000000_0111111), BitConverter.UInt32BitsToSingle(0x003F0000)), // just below middle subnormal (UInt16BitsToBFloat16(0b0_00000000_0000001), BitConverter.UInt32BitsToSingle(0x00010000)), // smallest subnormal (UInt16BitsToBFloat16(0b1_00000000_0000001), BitConverter.UInt32BitsToSingle(0x80010000)), // highest negative subnormal - (UInt16BitsToBFloat16(0b1_00000000_0111111), BitConverter.UInt32BitsToSingle(0x803F8000)), // just above negative middle subnormal + (UInt16BitsToBFloat16(0b1_00000000_0111111), BitConverter.UInt32BitsToSingle(0x803F0000)), // just above negative middle subnormal (UInt16BitsToBFloat16(0b1_00000000_1000000), BitConverter.UInt32BitsToSingle(0x80400000)), // negative middle subnormal (UInt16BitsToBFloat16(0b1_00000000_1111111), BitConverter.UInt32BitsToSingle(0x807F0000)), // lowest negative subnormal (UInt16BitsToBFloat16(0b1_00000001_0000000), BitConverter.UInt32BitsToSingle(0x80800000)) // highest negative normal @@ -216,8 +216,8 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() (-0f, UInt16BitsToBFloat16(0b1_00000000_0000000)), // -0 (42f, UInt16BitsToBFloat16(0b0_10000100_0101000)), // 42 (-42f, UInt16BitsToBFloat16(0b1_10000100_0101000)), // -42 - (0.1f, UInt16BitsToBFloat16(0b0_01111011_1001100)), // 0.0999755859375 - (-0.1f, UInt16BitsToBFloat16(0b1_01111011_1001100)), // -0.0999755859375 + (0.1f, UInt16BitsToBFloat16(0b0_01111011_1001101)), // 0.10009765625 + (-0.1f, UInt16BitsToBFloat16(0b1_01111011_1001101)), // -0.10009765625 (1.5f, UInt16BitsToBFloat16(0b0_01111111_1000000)), // 1.5 (-1.5f, UInt16BitsToBFloat16(0b1_01111111_1000000)), // -1.5 (1.5078125f, UInt16BitsToBFloat16(0b0_01111111_1000001)), // 1.5078125 @@ -225,7 +225,7 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() (BitConverter.UInt32BitsToSingle(0x00800000), UInt16BitsToBFloat16(0b0_00000001_0000000)), // smallest normal (BitConverter.UInt32BitsToSingle(0x007F0000), UInt16BitsToBFloat16(0b0_00000000_1111111)), // largest subnormal (BitConverter.UInt32BitsToSingle(0x00400000), UInt16BitsToBFloat16(0b0_00000000_1000000)), // middle subnormal - (BitConverter.UInt32BitsToSingle(0x003F8000), UInt16BitsToBFloat16(0b0_00000000_0111111)), // just below middle subnormal + (BitConverter.UInt32BitsToSingle(0x003F0000), UInt16BitsToBFloat16(0b0_00000000_0111111)), // just below middle subnormal (BitConverter.UInt32BitsToSingle(0x00010000), UInt16BitsToBFloat16(0b0_00000000_0000001)), // smallest subnormal (BitConverter.UInt32BitsToSingle(0x80010000), UInt16BitsToBFloat16(0b1_00000000_0000001)), // highest negative subnormal (BitConverter.UInt32BitsToSingle(0x803F0000), UInt16BitsToBFloat16(0b1_00000000_0111111)), // just above negative middle subnormal From 6df00e650c4f4d0968079fcc987865d9a369599a Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 21:38:16 +0800 Subject: [PATCH 14/67] Constants and well-known values --- .../src/System/Numerics/BFloat16.cs | 76 ++++++++++++++++--- 1 file changed, 66 insertions(+), 10 deletions(-) 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 368c5232be80d2..ecbaea141af4d4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -8,27 +8,83 @@ namespace System.Numerics /// public readonly struct BFloat16 : IComparable, + ISpanFormattable, IComparable, - IEquatable + IEquatable, + IBinaryFloatingPointIeee754, + IMinMaxValue, + IUtf8SpanFormattable, + IBinaryFloatParseAndFormatInfo { + // Constants for manipulating the private bit-representation + + internal const ushort SignMask = 0x8000; + internal const int SignShift = 15; + internal const byte ShiftedSignMask = SignMask >> SignShift; + + internal const ushort BiasedExponentMask = 0x7F80; + internal const int BiasedExponentShift = 7; + internal const int BiasedExponentLength = 8; + internal const byte ShiftedBiasedExponentMask = BiasedExponentMask >> BiasedExponentShift; + + internal const ushort TrailingSignificandMask = 0x007F; + + internal const byte MinSign = 0; + internal const byte MaxSign = 1; + + internal const byte MinBiasedExponent = 0x00; + internal const byte MaxBiasedExponent = 0xFF; + + internal const byte ExponentBias = 127; + + internal const sbyte MinExponent = -126; + internal const sbyte MaxExponent = +127; + + internal const ushort MinTrailingSignificand = 0x0000; + internal const ushort MaxTrailingSignificand = 0x007F; + + internal const int TrailingSignificandLength = 7; + internal const int SignificandLength = TrailingSignificandLength + 1; + + // Constants representing the private bit-representation for various default values + + private const ushort PositiveZeroBits = 0x0000; + private const ushort NegativeZeroBits = 0x8000; + private const ushort EpsilonBits = 0x0001; + private const ushort PositiveInfinityBits = 0x7F80; + private const ushort NegativeInfinityBits = 0xFF80; + + private const ushort PositiveQNaNBits = 0x7FC0; + private const ushort NegativeQNaNBits = 0xFFC0; + private const ushort MinValueBits = 0xFF7F; private const ushort MaxValueBits = 0x7F7F; - /// - /// Represents the smallest positive value that is greater than zero. - /// + private const ushort PositiveOneBits = 0x3F80; + private const ushort NegativeOneBits = 0xBF80; + + private const ushort SmallestNormalBits = 0x0080; + + private const ushort EBits = 0x402E; + private const ushort PiBits = 0x4049; + private const ushort TauBits = 0x40C9; + + // Well-defined and commonly used values + public static BFloat16 Epsilon => new BFloat16(EpsilonBits); - /// - /// Represents the smallest possible value of . - /// + public static BFloat16 PositiveInfinity => new BFloat16(PositiveInfinityBits); + + public static BFloat16 NegativeInfinity => new BFloat16(NegativeInfinityBits); + + public static BFloat16 NaN => new BFloat16(NegativeQNaNBits); + + /// public static BFloat16 MinValue => new BFloat16(MinValueBits); - /// - /// Represents the largest possible value of . - /// + /// public static BFloat16 MaxValue => new BFloat16(MaxValueBits); internal readonly ushort _value; From ff295fd196d902a874afeebb4d30d142cebaf932 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 21:48:45 +0800 Subject: [PATCH 15/67] Categorizing methods --- .../src/System/Numerics/BFloat16.cs | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) 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 ecbaea141af4d4..8b28e2c9145d15 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + namespace System.Numerics { /// @@ -134,6 +136,86 @@ public static explicit operator BFloat16(float value) // BFloat is effectively a truncation of Single, with lower 16 bits of mantissa truncated. // Delegating all operations to Single should be correct and effective. + // INumberBase + + /// Determines whether the specified value is finite (zero, subnormal, or normal). + /// This effectively checks the value is not NaN and not infinite. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFinite(BFloat16 value) + { + uint bits = value._value; + return (~bits & PositiveInfinityBits) != 0; + } + + /// Determines whether the specified value is infinite. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsInfinity(BFloat16 value) + { + uint bits = value._value; + return (bits & ~SignMask) == PositiveInfinityBits; + } + + /// Determines whether the specified value is NaN. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNaN(BFloat16 value) + { + uint bits = value._value; + return (bits & ~SignMask) > PositiveInfinityBits; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsNaNOrZero(BFloat16 value) + { + uint bits = value._value; + return ((bits - 1) & ~SignMask) >= PositiveInfinityBits; + } + + /// Determines whether the specified value is negative. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNegative(BFloat16 value) + { + return (short)(value._value) < 0; + } + + /// Determines whether the specified value is negative infinity. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNegativeInfinity(BFloat16 value) + { + return value._value == NegativeInfinityBits; + } + + /// Determines whether the specified value is normal (finite, but not zero or subnormal). + /// This effectively checks the value is not NaN, not infinite, not subnormal, and not zero. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNormal(BFloat16 value) + { + uint bits = value._value; + return (ushort)((bits & ~SignMask) - SmallestNormalBits) < (PositiveInfinityBits - SmallestNormalBits); + } + + /// Determines whether the specified value is positive infinity. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsPositiveInfinity(BFloat16 value) + { + return value._value == PositiveInfinityBits; + } + + /// Determines whether the specified value is subnormal (finite, but not zero or normal). + /// This effectively checks the value is not NaN, not infinite, not normal, and not zero. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsSubnormal(BFloat16 value) + { + uint bits = value._value; + return (ushort)((bits & ~SignMask) - 1) < MaxTrailingSignificand; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsZero(BFloat16 value) + { + uint bits = value._value; + return (bits & ~SignMask) == 0; + } + // Comparison /// From 09af2b200bdcfc9e0df034c6cc650d3fe5e4a379 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 21:51:46 +0800 Subject: [PATCH 16/67] Reorder conversion members --- .../src/System/Numerics/BFloat16.cs | 89 ++++++++++--------- 1 file changed, 46 insertions(+), 43 deletions(-) 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 8b28e2c9145d15..1d7db26fb3a843 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -93,49 +93,6 @@ public readonly struct BFloat16 internal BFloat16(ushort value) => _value = value; - // Casting - - /// Explicitly converts a value to its nearest representable value. - /// The value to convert. - /// converted to its nearest representable value. - public static explicit operator BFloat16(float value) - { - uint bits = BitConverter.SingleToUInt32Bits(value); - uint upper = bits >> 16; - // Only do rounding for finite numbers - if (float.IsFinite(value)) - { - uint lower = bits & 0xFFFF; - // Determine the increment for rounding - // When upper is even, midpoint (0x8000) will tie to no increment, which is effectively a decrement of lower - uint lowerShift = (~upper) & (lower >> 15) & 1; // Upper is even & lower>=0x8000 (not 0) - lower -= lowerShift; - uint increment = lower >> 15; - // Do the increment, MaxValue will be correctly increased to Infinity - upper += increment; - } - return new BFloat16((ushort)upper); - } - - /// Explicitly converts a value to its nearest representable value. - /// The value to convert. - /// converted to its nearest representable value. - public static explicit operator BFloat16(double value) => (BFloat16)(float)value; - - /// Explicitly converts a value to its nearest representable value. - /// The value to convert. - /// converted to its nearest representable value. - - public static explicit operator float(BFloat16 value) => BitConverter.Int32BitsToSingle(value._value << 16); - - /// Explicitly converts a value to its nearest representable value. - /// The value to convert. - /// converted to its nearest representable value. - public static explicit operator double(BFloat16 value) => (double)(float)value; - - // BFloat is effectively a truncation of Single, with lower 16 bits of mantissa truncated. - // Delegating all operations to Single should be correct and effective. - // INumberBase /// Determines whether the specified value is finite (zero, subnormal, or normal). @@ -277,5 +234,51 @@ public int CompareTo(object? obj) /// Returns a string representation of the current value. /// public override string ToString() => ((float)this).ToString(); + + // + // Explicit Convert To BFloat16 + // + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(float value) + { + uint bits = BitConverter.SingleToUInt32Bits(value); + uint upper = bits >> 16; + // Only do rounding for finite numbers + if (float.IsFinite(value)) + { + uint lower = bits & 0xFFFF; + // Determine the increment for rounding + // When upper is even, midpoint (0x8000) will tie to no increment, which is effectively a decrement of lower + uint lowerShift = (~upper) & (lower >> 15) & 1; // Upper is even & lower>=0x8000 (not 0) + lower -= lowerShift; + uint increment = lower >> 15; + // Do the increment, MaxValue will be correctly increased to Infinity + upper += increment; + } + return new BFloat16((ushort)upper); + } + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(double value) => (BFloat16)(float)value; + + // + // Explicit Convert From BFloat16 + // + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + + public static explicit operator float(BFloat16 value) => BitConverter.Int32BitsToSingle(value._value << 16); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator double(BFloat16 value) => (double)(float)value; } } From 1a8f0ad9dff972a4aacc4cf3ae30848668b28ffd Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 22:02:56 +0800 Subject: [PATCH 17/67] Operators batch 1 --- .../System.Private.CoreLib/src/System/Half.cs | 2 +- .../src/System/Numerics/BFloat16.cs | 627 ++++++++++++++++++ 2 files changed, 628 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index adc7df07932f7f..eceabbe016ec7b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1354,7 +1354,7 @@ int IFloatingPoint.GetExponentShortestBitLength() int IFloatingPoint.GetSignificandByteCount() => sizeof(ushort); /// - int IFloatingPoint.GetSignificandBitLength() => 11; + int IFloatingPoint.GetSignificandBitLength() => SignificandLength; /// bool IFloatingPoint.TryWriteExponentBigEndian(Span destination, out int bytesWritten) 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 1d7db26fb3a843..e5c4825a76f450 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1,7 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; +using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Numerics { @@ -93,6 +96,50 @@ public readonly struct BFloat16 internal BFloat16(ushort value) => _value = value; + internal byte BiasedExponent + { + get + { + ushort bits = _value; + return ExtractBiasedExponentFromBits(bits); + } + } + + internal sbyte Exponent + { + get + { + return (sbyte)(BiasedExponent - ExponentBias); + } + } + + internal ushort Significand + { + get + { + return (ushort)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U)); + } + } + + internal ushort TrailingSignificand + { + get + { + ushort bits = _value; + return ExtractTrailingSignificandFromBits(bits); + } + } + + internal static byte ExtractBiasedExponentFromBits(ushort bits) + { + return (byte)((bits >> BiasedExponentShift) & ShiftedBiasedExponentMask); + } + + internal static ushort ExtractTrailingSignificandFromBits(ushort bits) + { + return (ushort)(bits & TrailingSignificandMask); + } + // INumberBase /// Determines whether the specified value is finite (zero, subnormal, or normal). @@ -280,5 +327,585 @@ public static explicit operator BFloat16(float value) /// The value to convert. /// converted to its nearest representable value. public static explicit operator double(BFloat16 value) => (double)(float)value; + + // + // IAdditionOperators + // + + /// + public static BFloat16 operator +(BFloat16 left, BFloat16 right) => (BFloat16)((float)left + (float)right); + + // + // IAdditiveIdentity + // + + /// + static BFloat16 IAdditiveIdentity.AdditiveIdentity => new BFloat16(PositiveZeroBits); + + // + // IBinaryNumber + // + + /// + static BFloat16 IBinaryNumber.AllBitsSet => new BFloat16(0xFFFF); + + /// + public static bool IsPow2(BFloat16 value) + { + ushort bits = value._value; + + if ((short)bits <= 0) + { + // Zero and negative values cannot be powers of 2 + return false; + } + + byte biasedExponent = ExtractBiasedExponentFromBits(bits); + ushort trailingSignificand = ExtractTrailingSignificandFromBits(bits); + + if (biasedExponent == MinBiasedExponent) + { + // Subnormal values have 1 bit set when they're powers of 2 + return ushort.PopCount(trailingSignificand) == 1; + } + else if (biasedExponent == MaxBiasedExponent) + { + // NaN and Infinite values cannot be powers of 2 + return false; + } + + // Normal values have 0 bits set when they're powers of 2 + return trailingSignificand == MinTrailingSignificand; + } + + /// + public static BFloat16 Log2(BFloat16 value) => (BFloat16)MathF.Log2((float)value); + + // + // IBitwiseOperators + // + + /// + static BFloat16 IBitwiseOperators.operator &(BFloat16 left, BFloat16 right) + { + return new BFloat16((ushort)(left._value & right._value)); + } + + /// + static BFloat16 IBitwiseOperators.operator |(BFloat16 left, BFloat16 right) + { + return new BFloat16((ushort)(left._value | right._value)); + } + + /// + static BFloat16 IBitwiseOperators.operator ^(BFloat16 left, BFloat16 right) + { + return new BFloat16((ushort)(left._value ^ right._value)); + } + + /// + static BFloat16 IBitwiseOperators.operator ~(BFloat16 value) + { + return new BFloat16((ushort)(~value._value)); + } + + // + // IDecrementOperators + // + + /// + public static BFloat16 operator --(BFloat16 value) + { + var tmp = (float)value; + --tmp; + return (BFloat16)tmp; + } + + // + // IDivisionOperators + // + + /// + public static BFloat16 operator /(BFloat16 left, BFloat16 right) => (BFloat16)((float)left / (float)right); + + // + // IExponentialFunctions + // + + /// + public static BFloat16 Exp(BFloat16 x) => (BFloat16)MathF.Exp((float)x); + + /// + public static BFloat16 ExpM1(BFloat16 x) => (BFloat16)float.ExpM1((float)x); + + /// + public static BFloat16 Exp2(BFloat16 x) => (BFloat16)float.Exp2((float)x); + + /// + public static BFloat16 Exp2M1(BFloat16 x) => (BFloat16)float.Exp2M1((float)x); + + /// + public static BFloat16 Exp10(BFloat16 x) => (BFloat16)float.Exp10((float)x); + + /// + public static BFloat16 Exp10M1(BFloat16 x) => (BFloat16)float.Exp10M1((float)x); + + // + // IFloatingPoint + // + + /// + public static BFloat16 Ceiling(BFloat16 x) => (BFloat16)MathF.Ceiling((float)x); + + /// + public static BFloat16 Floor(BFloat16 x) => (BFloat16)MathF.Floor((float)x); + + /// + public static BFloat16 Round(BFloat16 x) => (BFloat16)MathF.Round((float)x); + + /// + public static BFloat16 Round(BFloat16 x, int digits) => (BFloat16)MathF.Round((float)x, digits); + + /// + public static BFloat16 Round(BFloat16 x, MidpointRounding mode) => (BFloat16)MathF.Round((float)x, mode); + + /// + public static BFloat16 Round(BFloat16 x, int digits, MidpointRounding mode) => (BFloat16)MathF.Round((float)x, digits, mode); + + /// + public static BFloat16 Truncate(BFloat16 x) => (BFloat16)MathF.Truncate((float)x); + + /// + int IFloatingPoint.GetExponentByteCount() => sizeof(sbyte); + + /// + int IFloatingPoint.GetExponentShortestBitLength() + { + sbyte exponent = Exponent; + + if (exponent >= 0) + { + return (sizeof(sbyte) * 8) - sbyte.LeadingZeroCount(exponent); + } + else + { + return (sizeof(sbyte) * 8) + 1 - sbyte.LeadingZeroCount((sbyte)(~exponent)); + } + } + + /// + int IFloatingPoint.GetSignificandByteCount() => sizeof(ushort); + + /// + int IFloatingPoint.GetSignificandBitLength() => SignificandLength; + + /// + bool IFloatingPoint.TryWriteExponentBigEndian(Span destination, out int bytesWritten) + { + if (destination.Length >= sizeof(sbyte)) + { + sbyte exponent = Exponent; + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), exponent); + + bytesWritten = sizeof(sbyte); + return true; + } + else + { + bytesWritten = 0; + return false; + } + } + + /// + bool IFloatingPoint.TryWriteExponentLittleEndian(Span destination, out int bytesWritten) + { + if (destination.Length >= sizeof(sbyte)) + { + sbyte exponent = Exponent; + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), exponent); + + bytesWritten = sizeof(sbyte); + return true; + } + else + { + bytesWritten = 0; + return false; + } + } + + /// + bool IFloatingPoint.TryWriteSignificandBigEndian(Span destination, out int bytesWritten) + { + if (destination.Length >= sizeof(ushort)) + { + ushort significand = Significand; + + if (BitConverter.IsLittleEndian) + { + significand = BinaryPrimitives.ReverseEndianness(significand); + } + + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), significand); + + bytesWritten = sizeof(ushort); + return true; + } + else + { + bytesWritten = 0; + return false; + } + } + + /// + bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destination, out int bytesWritten) + { + if (destination.Length >= sizeof(ushort)) + { + ushort significand = Significand; + + if (!BitConverter.IsLittleEndian) + { + significand = BinaryPrimitives.ReverseEndianness(significand); + } + + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), significand); + + bytesWritten = sizeof(ushort); + return true; + } + else + { + bytesWritten = 0; + return false; + } + } + + // + // IFloatingPointConstants + // + + /// + public static BFloat16 E => new BFloat16(EBits); + + /// + public static BFloat16 Pi => new BFloat16(PiBits); + + /// + public static BFloat16 Tau => new BFloat16(TauBits); + + // + // IFloatingPointIeee754 + // + + /// + public static BFloat16 NegativeZero => new BFloat16(NegativeZeroBits); + + /// + public static BFloat16 Atan2(BFloat16 y, BFloat16 x) => (BFloat16)MathF.Atan2((float)y, (float)x); + + /// + public static BFloat16 Atan2Pi(BFloat16 y, BFloat16 x) => (BFloat16)float.Atan2Pi((float)y, (float)x); + + /// + public static BFloat16 BitDecrement(BFloat16 x) + { + uint bits = x._value; + + if (!IsFinite(x)) + { + // NaN returns NaN + // -Infinity returns -Infinity + // +Infinity returns MaxValue + return (bits == PositiveInfinityBits) ? MaxValue : x; + } + + if (bits == PositiveZeroBits) + { + // +0.0 returns -Epsilon + return -Epsilon; + } + + // Negative values need to be incremented + // Positive values need to be decremented + + if (IsNegative(x)) + { + bits += 1; + } + else + { + bits -= 1; + } + return new BFloat16((ushort)bits); + } + + /// + public static BFloat16 BitIncrement(BFloat16 x) + { + uint bits = x._value; + + if (!IsFinite(x)) + { + // NaN returns NaN + // -Infinity returns MinValue + // +Infinity returns +Infinity + return (bits == NegativeInfinityBits) ? MinValue : x; + } + + if (bits == NegativeZeroBits) + { + // -0.0 returns Epsilon + return Epsilon; + } + + // Negative values need to be decremented + // Positive values need to be incremented + + if (IsNegative(x)) + { + bits -= 1; + } + else + { + bits += 1; + } + return new BFloat16((ushort)bits); + } + + /// + public static BFloat16 FusedMultiplyAdd(BFloat16 left, BFloat16 right, BFloat16 addend) => (BFloat16)MathF.FusedMultiplyAdd((float)left, (float)right, (float)addend); + + /// + public static BFloat16 Ieee754Remainder(BFloat16 left, BFloat16 right) => (BFloat16)MathF.IEEERemainder((float)left, (float)right); + + /// + public static int ILogB(BFloat16 x) + { + // This code is based on `ilogbf` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + if (!IsNormal(x)) // x is zero, subnormal, infinity, or NaN + { + if (IsZero(x)) + { + return int.MinValue; + } + + if (!IsFinite(x)) // infinity or NaN + { + return int.MaxValue; + } + + Debug.Assert(IsSubnormal(x)); + return MinExponent - (BitOperations.TrailingZeroCount(x.TrailingSignificand) - BiasedExponentLength); + } + + return x.Exponent; + } + + /// + public static BFloat16 Lerp(BFloat16 value1, BFloat16 value2, BFloat16 amount) => (BFloat16)float.Lerp((float)value1, (float)value2, (float)amount); + + /// + public static BFloat16 ReciprocalEstimate(BFloat16 x) => (BFloat16)MathF.ReciprocalEstimate((float)x); + + /// + public static BFloat16 ReciprocalSqrtEstimate(BFloat16 x) => (BFloat16)MathF.ReciprocalSqrtEstimate((float)x); + + /// + public static BFloat16 ScaleB(BFloat16 x, int n) => (BFloat16)MathF.ScaleB((float)x, n); + + // /// + // public static BFloat16 Compound(BFloat16 x, BFloat16 n) => (BFloat16)MathF.Compound((float)x, (float)n); + + // + // IHyperbolicFunctions + // + + /// + public static BFloat16 Acosh(BFloat16 x) => (BFloat16)MathF.Acosh((float)x); + + /// + public static BFloat16 Asinh(BFloat16 x) => (BFloat16)MathF.Asinh((float)x); + + /// + public static BFloat16 Atanh(BFloat16 x) => (BFloat16)MathF.Atanh((float)x); + + /// + public static BFloat16 Cosh(BFloat16 x) => (BFloat16)MathF.Cosh((float)x); + + /// + public static BFloat16 Sinh(BFloat16 x) => (BFloat16)MathF.Sinh((float)x); + + /// + public static BFloat16 Tanh(BFloat16 x) => (BFloat16)MathF.Tanh((float)x); + + // + // IIncrementOperators + // + + /// + public static BFloat16 operator ++(BFloat16 value) + { + var tmp = (float)value; + ++tmp; + return (BFloat16)tmp; + } + + // + // ILogarithmicFunctions + // + + /// + public static BFloat16 Log(BFloat16 x) => (BFloat16)MathF.Log((float)x); + + /// + public static BFloat16 Log(BFloat16 x, BFloat16 newBase) => (BFloat16)MathF.Log((float)x, (float)newBase); + + /// + public static BFloat16 Log10(BFloat16 x) => (BFloat16)MathF.Log10((float)x); + + /// + public static BFloat16 LogP1(BFloat16 x) => (BFloat16)float.LogP1((float)x); + + /// + public static BFloat16 Log2P1(BFloat16 x) => (BFloat16)float.Log2P1((float)x); + + /// + public static BFloat16 Log10P1(BFloat16 x) => (BFloat16)float.Log10P1((float)x); + + // + // IModulusOperators + // + + /// + public static BFloat16 operator %(BFloat16 left, BFloat16 right) => (BFloat16)((float)left % (float)right); + + // + // IMultiplicativeIdentity + // + + /// + public static BFloat16 MultiplicativeIdentity => new BFloat16(PositiveOneBits); + + // + // IMultiplyOperators + // + + /// + public static BFloat16 operator *(BFloat16 left, BFloat16 right) => (BFloat16)((float)left * (float)right); + + // + // INumber + // + + /// + public static BFloat16 Clamp(BFloat16 value, BFloat16 min, BFloat16 max) => (BFloat16)Math.Clamp((float)value, (float)min, (float)max); + + /// + public static BFloat16 CopySign(BFloat16 value, BFloat16 sign) + { + // This method is required to work for all inputs, + // including NaN, so we operate on the raw bits. + uint xbits = value._value; + uint ybits = sign._value; + + // Remove the sign from x, and remove everything but the sign from y + // Then, simply OR them to get the correct sign + return new BFloat16((ushort)((xbits & ~SignMask) | (ybits & SignMask))); + } + + /// + public static BFloat16 Max(BFloat16 x, BFloat16 y) => (BFloat16)MathF.Max((float)x, (float)y); + + /// + public static BFloat16 MaxNumber(BFloat16 x, BFloat16 y) + { + // This matches the IEEE 754:2019 `maximumNumber` function + // + // It does not propagate NaN inputs back to the caller and + // otherwise returns the larger of the inputs. It + // treats +0 as larger than -0 as per the specification. + + if (x != y) + { + if (!IsNaN(y)) + { + return y < x ? x : y; + } + + return x; + } + + return IsNegative(y) ? x : y; + } + + /// + public static BFloat16 Min(BFloat16 x, BFloat16 y) => (BFloat16)MathF.Min((float)x, (float)y); + + /// + public static BFloat16 MinNumber(BFloat16 x, BFloat16 y) + { + // This matches the IEEE 754:2019 `minimumNumber` function + // + // It does not propagate NaN inputs back to the caller and + // otherwise returns the larger of the inputs. It + // treats +0 as larger than -0 as per the specification. + + if (x != y) + { + if (!IsNaN(y)) + { + return x < y ? x : y; + } + + return x; + } + + return IsNegative(x) ? x : y; + } + + /// + public static int Sign(BFloat16 value) + { + if (IsNaN(value)) + { + throw new ArithmeticException(SR.Arithmetic_NaN); + } + + if (IsZero(value)) + { + return 0; + } + else if (IsNegative(value)) + { + return -1; + } + + return +1; + } + + // + // INumberBase + // + + /// + public static BFloat16 One => new BFloat16(PositiveOneBits); + + /// + static int INumberBase.Radix => 2; + + /// + public static BFloat16 Zero => new BFloat16(PositiveZeroBits); + + /// + public static BFloat16 Abs(BFloat16 value) => new BFloat16((ushort)(value._value & ~SignMask)); + } } From c9fc8677109fcc6ebbb7099c60b360f3912d36d7 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 22:05:43 +0800 Subject: [PATCH 18/67] Operators batch 2 --- .../src/System/Numerics/BFloat16.cs | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) 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 e5c4825a76f450..4f643b656a2dac 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -907,5 +907,153 @@ public static int Sign(BFloat16 value) /// public static BFloat16 Abs(BFloat16 value) => new BFloat16((ushort)(value._value & ~SignMask)); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BFloat16 CreateChecked(TOther value) + where TOther : INumberBase + { + BFloat16 result; + + if (typeof(TOther) == typeof(BFloat16)) + { + result = (BFloat16)(object)value; + } + else if (!TryConvertFrom(value, out result) && !TOther.TryConvertToChecked(value, out result)) + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BFloat16 CreateSaturating(TOther value) + where TOther : INumberBase + { + BFloat16 result; + + if (typeof(TOther) == typeof(BFloat16)) + { + result = (BFloat16)(object)value; + } + else if (!TryConvertFrom(value, out result) && !TOther.TryConvertToSaturating(value, out result)) + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BFloat16 CreateTruncating(TOther value) + where TOther : INumberBase + { + BFloat16 result; + + if (typeof(TOther) == typeof(BFloat16)) + { + result = (BFloat16)(object)value; + } + else if (!TryConvertFrom(value, out result) && !TOther.TryConvertToTruncating(value, out result)) + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + /// + static bool INumberBase.IsCanonical(BFloat16 value) => true; + + /// + static bool INumberBase.IsComplexNumber(BFloat16 value) => false; + + /// + public static bool IsEvenInteger(BFloat16 value) => float.IsEvenInteger((float)value); + + /// + static bool INumberBase.IsImaginaryNumber(BFloat16 value) => false; + + /// + public static bool IsInteger(BFloat16 value) => float.IsInteger((float)value); + + /// + public static bool IsOddInteger(BFloat16 value) => float.IsOddInteger((float)value); + + /// + public static bool IsPositive(BFloat16 value) => (short)(value._value) >= 0; + + /// + public static bool IsRealNumber(BFloat16 value) + { + // A NaN will never equal itself so this is an + // easy and efficient way to check for a real number. + +#pragma warning disable CS1718 + return value == value; +#pragma warning restore CS1718 + } + + /// + static bool INumberBase.IsZero(BFloat16 value) => IsZero(value); + + /// + public static BFloat16 MaxMagnitude(BFloat16 x, BFloat16 y) => (BFloat16)MathF.MaxMagnitude((float)x, (float)y); + + /// + public static BFloat16 MaxMagnitudeNumber(BFloat16 x, BFloat16 y) + { + // This matches the IEEE 754:2019 `maximumMagnitudeNumber` function + // + // It does not propagate NaN inputs back to the caller and + // otherwise returns the input with a larger magnitude. + // It treats +0 as larger than -0 as per the specification. + + BFloat16 ax = Abs(x); + BFloat16 ay = Abs(y); + + if ((ax > ay) || IsNaN(ay)) + { + return x; + } + + if (ax == ay) + { + return IsNegative(x) ? y : x; + } + + return y; + } + + /// + public static BFloat16 MinMagnitude(BFloat16 x, BFloat16 y) => (BFloat16)MathF.MinMagnitude((float)x, (float)y); + + /// + public static BFloat16 MinMagnitudeNumber(BFloat16 x, BFloat16 y) + { + // This matches the IEEE 754:2019 `minimumMagnitudeNumber` function + // + // It does not propagate NaN inputs back to the caller and + // otherwise returns the input with a larger magnitude. + // It treats +0 as larger than -0 as per the specification. + + BFloat16 ax = Abs(x); + BFloat16 ay = Abs(y); + + if ((ax < ay) || IsNaN(ay)) + { + return x; + } + + if (ax == ay) + { + return IsNegative(x) ? x : y; + } + + return y; + } + } } From e9fc0f8f3263707e36c861cd9c91a7da3803c480 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 22:09:38 +0800 Subject: [PATCH 19/67] TryConvert --- .../src/System/Numerics/BFloat16.cs | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) 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 4f643b656a2dac..0950f6fa466302 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -3,6 +3,7 @@ using System.Buffers.Binary; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -1055,5 +1056,236 @@ public static BFloat16 MinMagnitudeNumber(BFloat16 x, BFloat16 y) return y; } + private static bool TryConvertFrom(TOther value, out BFloat16 result) + where TOther : INumberBase + { + // In order to reduce overall code duplication and improve the inlinabilty of these + // methods for the corelib types we have `ConvertFrom` handle the same sign and + // `ConvertTo` handle the opposite sign. However, since there is an uneven split + // between signed and unsigned types, the one that handles unsigned will also + // handle `Decimal`. + // + // That is, `ConvertFrom` for `BFloat16` will handle the other signed types and + // `ConvertTo` will handle the unsigned types + + if (typeof(TOther) == typeof(double)) + { + double actualValue = (double)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(short)) + { + short actualValue = (short)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(int)) + { + int actualValue = (int)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(long)) + { + long actualValue = (long)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(Int128)) + { + Int128 actualValue = (Int128)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(nint)) + { + nint actualValue = (nint)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(sbyte)) + { + sbyte actualValue = (sbyte)(object)value; + result = actualValue; + return true; + } + else if (typeof(TOther) == typeof(float)) + { + float actualValue = (float)(object)value; + result = (BFloat16)actualValue; + return true; + } + else if (typeof(TOther) == typeof(Half)) + { + Half actualValue = (Half)(object)value; + result = (BFloat16)actualValue; + return true; + } + else + { + result = default; + return false; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertToChecked(BFloat16 value, [MaybeNullWhen(false)] out TOther result) + { + // In order to reduce overall code duplication and improve the inlinabilty of these + // methods for the corelib types we have `ConvertFrom` handle the same sign and + // `ConvertTo` handle the opposite sign. However, since there is an uneven split + // between signed and unsigned types, the one that handles unsigned will also + // handle `Decimal`. + // + // That is, `ConvertFrom` for `BFloat16` will handle the other signed types and + // `ConvertTo` will handle the unsigned types. + + if (typeof(TOther) == typeof(byte)) + { + byte actualResult = checked((byte)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(char)) + { + char actualResult = checked((char)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(decimal)) + { + decimal actualResult = checked((decimal)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(ushort)) + { + ushort actualResult = checked((ushort)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(uint)) + { + uint actualResult = checked((uint)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(ulong)) + { + ulong actualResult = checked((ulong)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(UInt128)) + { + UInt128 actualResult = checked((UInt128)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(nuint)) + { + nuint actualResult = checked((nuint)value); + result = (TOther)(object)actualResult; + return true; + } + else + { + result = default; + return false; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertToSaturating(BFloat16 value, [MaybeNullWhen(false)] out TOther result) + { + return TryConvertTo(value, out result); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertToTruncating(BFloat16 value, [MaybeNullWhen(false)] out TOther result) + { + return TryConvertTo(value, out result); + } + + private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] out TOther result) + where TOther : INumberBase + { + // In order to reduce overall code duplication and improve the inlinabilty of these + // methods for the corelib types we have `ConvertFrom` handle the same sign and + // `ConvertTo` handle the opposite sign. However, since there is an uneven split + // between signed and unsigned types, the one that handles unsigned will also + // handle `Decimal`. + // + // That is, `ConvertFrom` for `BFloat16` will handle the other signed types and + // `ConvertTo` will handle the unsigned types + + if (typeof(TOther) == typeof(byte)) + { + var actualResult = (value >= byte.MaxValue) ? byte.MaxValue : + (value <= byte.MinValue) ? byte.MinValue : (byte)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(char)) + { + char actualResult = (value == PositiveInfinity) ? char.MaxValue : + (value <= Zero) ? char.MinValue : (char)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(decimal)) + { + decimal actualResult = (value == PositiveInfinity) ? decimal.MaxValue : + (value == NegativeInfinity) ? decimal.MinValue : + IsNaN(value) ? 0.0m : (decimal)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(ushort)) + { + ushort actualResult = (value == PositiveInfinity) ? ushort.MaxValue : + (value <= Zero) ? ushort.MinValue : (ushort)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(uint)) + { + uint actualResult = (value == PositiveInfinity) ? uint.MaxValue : + (value <= Zero) ? uint.MinValue : (uint)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(ulong)) + { + ulong actualResult = (value == PositiveInfinity) ? ulong.MaxValue : + (value <= Zero) ? ulong.MinValue : + IsNaN(value) ? 0 : (ulong)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(UInt128)) + { + UInt128 actualResult = (value == PositiveInfinity) ? UInt128.MaxValue : + (value <= Zero) ? UInt128.MinValue : (UInt128)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(nuint)) + { + nuint actualResult = (value == PositiveInfinity) ? nuint.MaxValue : + (value <= Zero) ? nuint.MinValue : (nuint)value; + result = (TOther)(object)actualResult; + return true; + } + else + { + result = default; + return false; + } + } } } From c967aa5904236f8abe3efd7993a0dda3424e5956 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 21 Feb 2024 22:11:26 +0800 Subject: [PATCH 20/67] Operators batch 3 --- .../src/System/Numerics/BFloat16.cs | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) 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 0950f6fa466302..6566fa03c3f25e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -4,6 +4,7 @@ using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,6 +23,8 @@ public readonly struct BFloat16 IUtf8SpanFormattable, IBinaryFloatParseAndFormatInfo { + private const NumberStyles DefaultParseStyle = NumberStyles.Float | NumberStyles.AllowThousands; + // Constants for manipulating the private bit-representation internal const ushort SignMask = 0x8000; @@ -1287,5 +1290,170 @@ private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] return false; } } + + // + // IParsable + // + + /// + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out BFloat16 result) => TryParse(s, DefaultParseStyle, provider, out result); + + // + // IPowerFunctions + // + + /// + public static BFloat16 Pow(BFloat16 x, BFloat16 y) => (BFloat16)MathF.Pow((float)x, (float)y); + + // + // IRootFunctions + // + + /// + public static BFloat16 Cbrt(BFloat16 x) => (BFloat16)MathF.Cbrt((float)x); + + /// + public static BFloat16 Hypot(BFloat16 x, BFloat16 y) => (BFloat16)float.Hypot((float)x, (float)y); + + /// + public static BFloat16 RootN(BFloat16 x, int n) => (BFloat16)float.RootN((float)x, n); + + /// + public static BFloat16 Sqrt(BFloat16 x) => (BFloat16)MathF.Sqrt((float)x); + + // + // ISignedNumber + // + + /// + public static BFloat16 NegativeOne => new BFloat16(NegativeOneBits); + + // + // ISpanParsable + // + + /// + public static BFloat16 Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, DefaultParseStyle, provider); + + /// + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out BFloat16 result) => TryParse(s, DefaultParseStyle, provider, out result); + + // + // ISubtractionOperators + // + + /// + public static BFloat16 operator -(BFloat16 left, BFloat16 right) => (BFloat16)((float)left - (float)right); + + // + // ITrigonometricFunctions + // + + /// + public static BFloat16 Acos(BFloat16 x) => (BFloat16)MathF.Acos((float)x); + + /// + public static BFloat16 AcosPi(BFloat16 x) => (BFloat16)float.AcosPi((float)x); + + /// + public static BFloat16 Asin(BFloat16 x) => (BFloat16)MathF.Asin((float)x); + + /// + public static BFloat16 AsinPi(BFloat16 x) => (BFloat16)float.AsinPi((float)x); + + /// + public static BFloat16 Atan(BFloat16 x) => (BFloat16)MathF.Atan((float)x); + + /// + public static BFloat16 AtanPi(BFloat16 x) => (BFloat16)float.AtanPi((float)x); + + /// + public static BFloat16 Cos(BFloat16 x) => (BFloat16)MathF.Cos((float)x); + + /// + public static BFloat16 CosPi(BFloat16 x) => (BFloat16)float.CosPi((float)x); + + /// + public static BFloat16 DegreesToRadians(BFloat16 degrees) + { + // NOTE: Don't change the algorithm without consulting the DIM + // which elaborates on why this implementation was chosen + + return (BFloat16)float.DegreesToRadians((float)degrees); + } + + /// + public static BFloat16 RadiansToDegrees(BFloat16 radians) + { + // NOTE: Don't change the algorithm without consulting the DIM + // which elaborates on why this implementation was chosen + + return (BFloat16)float.RadiansToDegrees((float)radians); + } + + /// + public static BFloat16 Sin(BFloat16 x) => (BFloat16)MathF.Sin((float)x); + + /// + public static (BFloat16 Sin, BFloat16 Cos) SinCos(BFloat16 x) + { + var (sin, cos) = MathF.SinCos((float)x); + return ((BFloat16)sin, (BFloat16)cos); + } + + /// + public static (BFloat16 SinPi, BFloat16 CosPi) SinCosPi(BFloat16 x) + { + var (sinPi, cosPi) = float.SinCosPi((float)x); + return ((BFloat16)sinPi, (BFloat16)cosPi); + } + + /// + public static BFloat16 SinPi(BFloat16 x) => (BFloat16)float.SinPi((float)x); + + /// + public static BFloat16 Tan(BFloat16 x) => (BFloat16)MathF.Tan((float)x); + + /// + public static BFloat16 TanPi(BFloat16 x) => (BFloat16)float.TanPi((float)x); + + // + // IUnaryNegationOperators + // + + /// + public static BFloat16 operator -(BFloat16 value) => (BFloat16)(-(float)value); + + // + // IUnaryPlusOperators + // + + /// + public static BFloat16 operator +(BFloat16 value) => value; + + // + // IUtf8SpanParsable + // + + /// + public static BFloat16 Parse(ReadOnlySpan utf8Text, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + { + NumberFormatInfo.ValidateParseStyleInteger(style); + return Number.ParseFloat(utf8Text, style, NumberFormatInfo.GetInstance(provider)); + } + + /// + public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFormatProvider? provider, out BFloat16 result) + { + NumberFormatInfo.ValidateParseStyleInteger(style); + return Number.TryParseFloat(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result); + } + + /// + public static BFloat16 Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) => Parse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + /// + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, out BFloat16 result) => TryParse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + } } From 17c13c088707174e5016926f1cdf7f526ef965ca Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 22 Feb 2024 02:07:17 +0800 Subject: [PATCH 21/67] Parsing and formatting --- .../src/System/Double.cs | 2 +- .../System.Private.CoreLib/src/System/Half.cs | 6 +- .../src/System/Numerics/BFloat16.cs | 190 ++++++++++++++++++ .../src/System/Single.cs | 2 +- 4 files changed, 195 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 71d73546bc1364..670fd1f865cbd1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -2287,7 +2287,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -342; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -324; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 308; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -4; diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index eceabbe016ec7b..95896ad046902f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -2330,7 +2330,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static int IBinaryFloatParseAndFormatInfo.NumberBufferLength => Number.HalfNumberBufferLength; static ulong IBinaryFloatParseAndFormatInfo.ZeroBits => 0; - static ulong IBinaryFloatParseAndFormatInfo.InfinityBits => 0x7C00; + static ulong IBinaryFloatParseAndFormatInfo.InfinityBits => PositiveInfinityBits; static ulong IBinaryFloatParseAndFormatInfo.NormalMantissaMask => (1UL << SignificandLength) - 1; static ulong IBinaryFloatParseAndFormatInfo.DenormalMantissaMask => TrailingSignificandMask; @@ -2342,10 +2342,10 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static int IBinaryFloatParseAndFormatInfo.MaxDecimalExponent => 5; static int IBinaryFloatParseAndFormatInfo.ExponentBias => ExponentBias; - static ushort IBinaryFloatParseAndFormatInfo.ExponentBits => 5; + static ushort IBinaryFloatParseAndFormatInfo.ExponentBits => BiasedExponentLength; static int IBinaryFloatParseAndFormatInfo.OverflowDecimalExponent => (MaxExponent + (2 * SignificandLength)) / 3; - static int IBinaryFloatParseAndFormatInfo.InfinityExponent => 0x1F; + static int IBinaryFloatParseAndFormatInfo.InfinityExponent => MaxBiasedExponent; static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; 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 6566fa03c3f25e..25140a8bdfe82c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -224,6 +224,114 @@ public static bool IsZero(BFloat16 value) return (bits & ~SignMask) == 0; } + /// + /// Parses a from a in the default parse style. + /// + /// The input to be parsed. + /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. + public static BFloat16 Parse(string s) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null); + + /// + /// Parses a from a in the given . + /// + /// The input to be parsed. + /// The used to parse the input. + /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. + public static BFloat16 Parse(string s, NumberStyles style) => Parse(s, style, provider: null); + + /// + /// Parses a from a and . + /// + /// The input to be parsed. + /// A format provider. + /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. + public static BFloat16 Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + + /// + /// Parses a from a with the given and . + /// + /// The input to be parsed. + /// The used to parse the input. + /// A format provider. + /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. + public static BFloat16 Parse(string s, NumberStyles style = DefaultParseStyle, IFormatProvider? provider = null) + { + if (s is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); + } + return Parse(s.AsSpan(), style, provider); + } + + /// + /// Parses a from a and . + /// + /// The input to be parsed. + /// The used to parse the input. + /// A format provider. + /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. + public static BFloat16 Parse(ReadOnlySpan s, NumberStyles style = DefaultParseStyle, IFormatProvider? provider = null) + { + NumberFormatInfo.ValidateParseStyleFloatingPoint(style); + return Number.ParseFloat(s, style, NumberFormatInfo.GetInstance(provider)); + } + + /// + /// Tries to parse a from a in the default parse style. + /// + /// The input to be parsed. + /// The equivalent value representing the input string if the parse was successful. If the input exceeds BFloat16's range, a or is returned. If the parse was unsuccessful, a default value is returned. + /// if the parse was successful, otherwise. + public static bool TryParse([NotNullWhen(true)] string? s, out BFloat16 result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); + + /// + /// Tries to parse a from a in the default parse style. + /// + /// The input to be parsed. + /// The equivalent value representing the input string if the parse was successful. If the input exceeds BFloat16's range, a or is returned. If the parse was unsuccessful, a default value is returned. + /// if the parse was successful, otherwise. + public static bool TryParse(ReadOnlySpan s, out BFloat16 result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); + + /// Tries to convert a UTF-8 character span containing the string representation of a number to its BFloat16-precision floating-point number equivalent. + /// A read-only UTF-8 character span that contains the number to convert. + /// When this method returns, contains a BFloat16-precision floating-point number equivalent of the numeric value or symbol contained in if the conversion succeeded or zero if the conversion failed. The conversion fails if the is or is not in a valid format. This parameter is passed uninitialized; any value originally supplied in result will be overwritten. + /// true if was converted successfully; otherwise, false. + public static bool TryParse(ReadOnlySpan utf8Text, out BFloat16 result) => TryParse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); + + /// + /// Tries to parse a from a with the given and . + /// + /// The input to be parsed. + /// The used to parse the input. + /// A format provider. + /// The equivalent value representing the input string if the parse was successful. If the input exceeds BFloat16's range, a or is returned. If the parse was unsuccessful, a default value is returned. + /// if the parse was successful, otherwise. + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out BFloat16 result) + { + NumberFormatInfo.ValidateParseStyleFloatingPoint(style); + + if (s == null) + { + result = Zero; + return false; + } + return Number.TryParseFloat(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result); + } + + /// + /// Tries to parse a from a with the given and . + /// + /// The input to be parsed. + /// The used to parse the input. + /// A format provider. + /// The equivalent value representing the input string if the parse was successful. If the input exceeds BFloat16's range, a or is returned. If the parse was unsuccessful, a default value is returned. + /// if the parse was successful, otherwise. + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out BFloat16 result) + { + NumberFormatInfo.ValidateParseStyleFloatingPoint(style); + return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result); + } + // Comparison /// @@ -286,6 +394,49 @@ public int CompareTo(object? obj) /// public override string ToString() => ((float)this).ToString(); + /// + /// Returns a string representation of the current value using the specified . + /// + public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) + { + return Number.FormatBFloat16(this, format, NumberFormatInfo.CurrentInfo); + } + + /// + /// Returns a string representation of the current value with the specified . + /// + public string ToString(IFormatProvider? provider) + { + return Number.FormatBFloat16(this, null, NumberFormatInfo.GetInstance(provider)); + } + + /// + /// Returns a string representation of the current value using the specified and . + /// + public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) + { + return Number.FormatBFloat16(this, format, NumberFormatInfo.GetInstance(provider)); + } + + /// + /// Tries to format the value of the current BFloat16 instance into the provided span of characters. + /// + /// When this method returns, this instance's value formatted as a span of characters. + /// When this method returns, the number of characters that were written in . + /// A span containing the characters that represent a standard or custom format string that defines the acceptable format for . + /// An optional object that supplies culture-specific formatting information for . + /// + public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) + { + return Number.TryFormatBFloat16(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); + } + + /// + public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) + { + return Number.TryFormatBFloat16(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); + } + // // Explicit Convert To BFloat16 // @@ -1455,5 +1606,44 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo /// public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, out BFloat16 result) => TryParse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + // + // IBinaryFloatParseAndFormatInfo + // + + static int IBinaryFloatParseAndFormatInfo.NumberBufferLength => Number.BFloat16NumberBufferLength; + + static ulong IBinaryFloatParseAndFormatInfo.ZeroBits => 0; + static ulong IBinaryFloatParseAndFormatInfo.InfinityBits => PositiveInfinityBits; + + static ulong IBinaryFloatParseAndFormatInfo.NormalMantissaMask => (1UL << SignificandLength) - 1; + static ulong IBinaryFloatParseAndFormatInfo.DenormalMantissaMask => TrailingSignificandMask; + + static int IBinaryFloatParseAndFormatInfo.MinBinaryExponent => 1 - MaxExponent; + static int IBinaryFloatParseAndFormatInfo.MaxBinaryExponent => MaxExponent; + + static int IBinaryFloatParseAndFormatInfo.MinDecimalExponent => -41; + static int IBinaryFloatParseAndFormatInfo.MaxDecimalExponent => 39; + + static int IBinaryFloatParseAndFormatInfo.ExponentBias => ExponentBias; + static ushort IBinaryFloatParseAndFormatInfo.ExponentBits => BiasedExponentLength; + + static int IBinaryFloatParseAndFormatInfo.OverflowDecimalExponent => (MaxExponent + (2 * SignificandLength)) / 3; + static int IBinaryFloatParseAndFormatInfo.InfinityExponent => MaxBiasedExponent; + + static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; + static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; + + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -41; + static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 38; + + static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -24; + static int IBinaryFloatParseAndFormatInfo.MaxExponentRoundToEven => 3; + + static int IBinaryFloatParseAndFormatInfo.MaxExponentFastPath => 3; + static ulong IBinaryFloatParseAndFormatInfo.MaxMantissaFastPath => 2UL << TrailingSignificandLength; + + static BFloat16 IBinaryFloatParseAndFormatInfo.BitsToFloat(ulong bits) => new BFloat16((ushort)(bits)); + + static ulong IBinaryFloatParseAndFormatInfo.FloatToBits(BFloat16 value) => value._value; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 9cc7c6b56c0adf..e69c8b02daae0c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -2167,7 +2167,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -65; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -45; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 38; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -17; From ad780a022f2208a2d797a7ed42e889aabb2aa45f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 22 Feb 2024 02:39:56 +0800 Subject: [PATCH 22/67] Add comments about how to determine parse and format info --- .../src/System/Number.Parsing.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index 952733c9268df9..7cc35e9247e4a5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -61,8 +61,8 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract int MinBinaryExponent { get; } static abstract int MaxBinaryExponent { get; } - static abstract int MinDecimalExponent { get; } - static abstract int MaxDecimalExponent { get; } + static abstract int MinDecimalExponent { get; } // Floor(Log10(Epsilon)) + static abstract int MaxDecimalExponent { get; } // Ceiling(Log10(MaxValue)) static abstract int ExponentBias { get; } static abstract ushort ExponentBits { get; } @@ -73,13 +73,13 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract ushort NormalMantissaBits { get; } static abstract ushort DenormalMantissaBits { get; } - static abstract int MinFastFloatDecimalExponent { get; } - static abstract int MaxFastFloatDecimalExponent { get; } + static abstract int MinFastFloatDecimalExponent { get; } // MinDecimalExponent + static abstract int MaxFastFloatDecimalExponent { get; } // MaxDecimalExponent - 1 - static abstract int MinExponentRoundToEven { get; } - static abstract int MaxExponentRoundToEven { get; } + static abstract int MinExponentRoundToEven { get; } // -Floor(Log2(2^(64 - NormalMantissaBits))) + static abstract int MaxExponentRoundToEven { get; } // Floor(Log5(2^(NormalMantissaBits + 1))) - static abstract int MaxExponentFastPath { get; } + static abstract int MaxExponentFastPath { get; } // Max(n) when 10^n can be precisely represented static abstract ulong MaxMantissaFastPath { get; } static abstract TSelf BitsToFloat(ulong bits); From c01949f08773e84f66fca28a56c10d7a25164b46 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 22 Feb 2024 02:41:30 +0800 Subject: [PATCH 23/67] Add missing interface implementations --- .../src/System/Numerics/BFloat16.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 25140a8bdfe82c..4281d5fac46fdd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1210,6 +1210,27 @@ public static BFloat16 MinMagnitudeNumber(BFloat16 x, BFloat16 y) return y; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertFromChecked(TOther value, out BFloat16 result) + { + return TryConvertFrom(value, out result); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertFromSaturating(TOther value, out BFloat16 result) + { + return TryConvertFrom(value, out result); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertFromTruncating(TOther value, out BFloat16 result) + { + return TryConvertFrom(value, out result); + } + private static bool TryConvertFrom(TOther value, out BFloat16 result) where TOther : INumberBase { From b63c1df511cf7e73f9965cb0830a56a88ad4a960 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 22 Feb 2024 03:05:01 +0800 Subject: [PATCH 24/67] NumberBufferLength --- src/libraries/Common/src/System/Number.NumberBuffer.cs | 1 + .../System.Private.CoreLib/src/System/Number.Parsing.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libraries/Common/src/System/Number.NumberBuffer.cs b/src/libraries/Common/src/System/Number.NumberBuffer.cs index 5b4fc7a7564e8f..9df0e5c4771ba6 100644 --- a/src/libraries/Common/src/System/Number.NumberBuffer.cs +++ b/src/libraries/Common/src/System/Number.NumberBuffer.cs @@ -21,6 +21,7 @@ internal static partial class Number internal const int UInt32NumberBufferLength = 10 + 1; // 10 for the longest input: 4,294,967,295 internal const int UInt64NumberBufferLength = 20 + 1; // 20 for the longest input: 18,446,744,073,709,551,615 internal const int UInt128NumberBufferLength = 39 + 1; // 39 for the longest input: 340,282,366,920,938,463,463,374,607,431,768,211,455 + internal const int BFloat16NumberBufferLength = 96 + 1 + 1; // 96 for the longest input + 1 for rounding (+1 for the null terminator) internal unsafe ref struct NumberBuffer { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index 7cc35e9247e4a5..34b4c8926437bf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -50,6 +50,7 @@ internal interface IBinaryIntegerParseAndFormatInfo : IBinaryInteger : IBinaryFloatingPointIeee754, IMinMaxValue where TSelf : unmanaged, IBinaryFloatParseAndFormatInfo { + // The significant digits count for (BiasedExponent=1, TrailingSignificand=all bits set), plus 2 static abstract int NumberBufferLength { get; } static abstract ulong ZeroBits { get; } From 754a3c8b09d5f93e0b04274f2b61b9f81e220d5b Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 22 Feb 2024 23:10:10 +0800 Subject: [PATCH 25/67] Add more comment --- src/libraries/System.Private.CoreLib/src/System/Double.cs | 2 +- .../System.Private.CoreLib/src/System/Number.Parsing.cs | 7 +++---- src/libraries/System.Private.CoreLib/src/System/Single.cs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 670fd1f865cbd1..71d73546bc1364 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -2287,7 +2287,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -324; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -342; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 308; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -4; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index 34b4c8926437bf..e0e22220d2194e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -50,8 +50,7 @@ internal interface IBinaryIntegerParseAndFormatInfo : IBinaryInteger : IBinaryFloatingPointIeee754, IMinMaxValue where TSelf : unmanaged, IBinaryFloatParseAndFormatInfo { - // The significant digits count for (BiasedExponent=1, TrailingSignificand=all bits set), plus 2 - static abstract int NumberBufferLength { get; } + static abstract int NumberBufferLength { get; } // Ceiling(Log10(5^(Abs(MinBinaryExponent) - 1))) + NormalMantissaBits + 1 + 1 static abstract ulong ZeroBits { get; } static abstract ulong InfinityBits { get; } @@ -74,10 +73,10 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract ushort NormalMantissaBits { get; } static abstract ushort DenormalMantissaBits { get; } - static abstract int MinFastFloatDecimalExponent { get; } // MinDecimalExponent + static abstract int MinFastFloatDecimalExponent { get; } // Floor(Log10(2^(MinBinaryExponent-DenormalMantissaBits-64))) static abstract int MaxFastFloatDecimalExponent { get; } // MaxDecimalExponent - 1 - static abstract int MinExponentRoundToEven { get; } // -Floor(Log2(2^(64 - NormalMantissaBits))) + static abstract int MinExponentRoundToEven { get; } // -Floor(Log5(2^(64 - NormalMantissaBits))) static abstract int MaxExponentRoundToEven { get; } // Floor(Log5(2^(NormalMantissaBits + 1))) static abstract int MaxExponentFastPath { get; } // Max(n) when 10^n can be precisely represented diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index e69c8b02daae0c..9cc7c6b56c0adf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -2167,7 +2167,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -45; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -65; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 38; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -17; From bcc260fab437dd79e8c08cd5fbc706dc6e9d4a14 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 24 Feb 2024 20:49:49 +0800 Subject: [PATCH 26/67] Correct MinFastFloatDecimalExponent --- src/libraries/System.Private.CoreLib/src/System/Half.cs | 2 +- .../System.Private.CoreLib/src/System/Number.Parsing.cs | 2 +- .../System.Private.CoreLib/src/System/Numerics/BFloat16.cs | 2 +- src/libraries/System.Private.CoreLib/src/System/Single.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 95896ad046902f..3130b7b94a89ec 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -2350,7 +2350,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -8; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -26; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 4; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -21; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index e0e22220d2194e..387f03ab750fcd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -73,7 +73,7 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract ushort NormalMantissaBits { get; } static abstract ushort DenormalMantissaBits { get; } - static abstract int MinFastFloatDecimalExponent { get; } // Floor(Log10(2^(MinBinaryExponent-DenormalMantissaBits-64))) + static abstract int MinFastFloatDecimalExponent { get; } // Ceiling(Log10(2^(MinBinaryExponent - 1 - DenormalMantissaBits - 64))) static abstract int MaxFastFloatDecimalExponent { get; } // MaxDecimalExponent - 1 static abstract int MinExponentRoundToEven { get; } // -Floor(Log5(2^(64 - NormalMantissaBits))) 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 4281d5fac46fdd..caea4678a0bc72 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1654,7 +1654,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -41; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -59; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 38; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -24; diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 9cc7c6b56c0adf..108c6b1d60b0ff 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -2167,7 +2167,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ushort IBinaryFloatParseAndFormatInfo.NormalMantissaBits => SignificandLength; static ushort IBinaryFloatParseAndFormatInfo.DenormalMantissaBits => TrailingSignificandLength; - static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -65; + static int IBinaryFloatParseAndFormatInfo.MinFastFloatDecimalExponent => -64; static int IBinaryFloatParseAndFormatInfo.MaxFastFloatDecimalExponent => 38; static int IBinaryFloatParseAndFormatInfo.MinExponentRoundToEven => -17; From 5a3d20068d0f4c2deced9b2a7384bb967185ab46 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 24 Feb 2024 21:52:04 +0800 Subject: [PATCH 27/67] Add explicit conversion to --- .../src/System/Numerics/BFloat16.cs | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) 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 caea4678a0bc72..a6d87f8fc06db0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -292,9 +292,9 @@ public static BFloat16 Parse(ReadOnlySpan s, NumberStyles style = DefaultP /// if the parse was successful, otherwise. public static bool TryParse(ReadOnlySpan s, out BFloat16 result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); - /// Tries to convert a UTF-8 character span containing the string representation of a number to its BFloat16-precision floating-point number equivalent. + /// Tries to convert a UTF-8 character span containing the string representation of a number to its number equivalent. /// A read-only UTF-8 character span that contains the number to convert. - /// When this method returns, contains a BFloat16-precision floating-point number equivalent of the numeric value or symbol contained in if the conversion succeeded or zero if the conversion failed. The conversion fails if the is or is not in a valid format. This parameter is passed uninitialized; any value originally supplied in result will be overwritten. + /// When this method returns, contains a number equivalent of the numeric value or symbol contained in if the conversion succeeded or zero if the conversion failed. The conversion fails if the is or is not in a valid format. This parameter is passed uninitialized; any value originally supplied in result will be overwritten. /// true if was converted successfully; otherwise, false. public static bool TryParse(ReadOnlySpan utf8Text, out BFloat16 result) => TryParse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); @@ -441,6 +441,46 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS // Explicit Convert To BFloat16 // + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(char value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(decimal value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(double value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(short value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(Half value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(int value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(long value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(nint value) => (BFloat16)(float)value; + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. @@ -463,10 +503,29 @@ public static explicit operator BFloat16(float value) return new BFloat16((ushort)upper); } - /// Explicitly converts a value to its nearest representable value. + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(double value) => (BFloat16)(float)value; + [CLSCompliant(false)] + public static explicit operator BFloat16(ushort value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator BFloat16(uint value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator BFloat16(ulong value) => (BFloat16)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator BFloat16(nuint value) => (BFloat16)(float)value; // // Explicit Convert From BFloat16 From c420dd3e9e64f6808323bf7e3fdb2d16e8094386 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 24 Feb 2024 21:57:38 +0800 Subject: [PATCH 28/67] Explicit convert from --- .../src/System/Numerics/BFloat16.cs | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) 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 a6d87f8fc06db0..8702d8682f2414 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -531,6 +531,185 @@ public static explicit operator BFloat16(float value) // Explicit Convert From BFloat16 // + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator byte(BFloat16 value) => (byte)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked byte(BFloat16 value) => checked((byte)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator char(BFloat16 value) => (char)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked char(BFloat16 value) => checked((char)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator decimal(BFloat16 value) => (decimal)(float)value; + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator short(BFloat16 value) => (short)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked short(BFloat16 value) => checked((short)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator int(BFloat16 value) => (int)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked int(BFloat16 value) => checked((int)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator long(BFloat16 value) => (long)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked long(BFloat16 value) => checked((long)(float)value); + + /// Explicitly converts a value to its nearest representable . + /// The value to convert. + /// converted to a 128-bit signed integer. + public static explicit operator Int128(BFloat16 value) => (Int128)(double)(value); + + /// Explicitly converts a value to its nearest representable , throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to a 128-bit signed integer. + /// is not representable by . + public static explicit operator checked Int128(BFloat16 value) => checked((Int128)(double)(value)); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator nint(BFloat16 value) => (nint)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked nint(BFloat16 value) => checked((nint)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator sbyte(BFloat16 value) => (sbyte)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked sbyte(BFloat16 value) => checked((sbyte)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator ushort(BFloat16 value) => (ushort)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked ushort(BFloat16 value) => checked((ushort)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator uint(BFloat16 value) => (uint)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked uint(BFloat16 value) => checked((uint)(float)value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator ulong(BFloat16 value) => (ulong)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked ulong(BFloat16 value) => checked((ulong)(float)value); + + /// Explicitly converts a value to its nearest representable . + /// The value to convert. + /// converted to a 128-bit unsigned integer. + [CLSCompliant(false)] + public static explicit operator UInt128(BFloat16 value) => (UInt128)(double)(value); + + /// Explicitly converts a value to its nearest representable , throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to a 128-bit unsigned integer. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked UInt128(BFloat16 value) => checked((UInt128)(double)(value)); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator nuint(BFloat16 value) => (nuint)(float)value; + + /// Explicitly converts a value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked nuint(BFloat16 value) => checked((nuint)(float)value); + + // + // Implicit Convert To BFloat16 + // + + /// Implicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static implicit operator BFloat16(byte value) => (BFloat16)(float)value; + + /// Implicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static implicit operator BFloat16(sbyte value) => (BFloat16)(float)value; + + // + // Implicit Convert From Half (actually explicit) + // + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. From 13e65d1cadb9471cc661d4fae3b77ca0e9500809 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 00:56:49 +0800 Subject: [PATCH 29/67] Fullfill casting operators --- .../src/System/Numerics/BFloat16.cs | 132 ++++++++++++++---- 1 file changed, 104 insertions(+), 28 deletions(-) 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 8702d8682f2414..281324cad05693 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -476,6 +476,11 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS /// converted to its nearest representable value. public static explicit operator BFloat16(long value) => (BFloat16)(float)value; + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator BFloat16(Int128 value) => (BFloat16)(float)value; + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. @@ -527,6 +532,12 @@ public static explicit operator BFloat16(float value) [CLSCompliant(false)] public static explicit operator BFloat16(nuint value) => (BFloat16)(float)value; + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator BFloat16(UInt128 value) => (BFloat16)(float)value; + // // Explicit Convert From BFloat16 // @@ -1546,15 +1557,45 @@ private static bool TryConvertFrom(TOther value, out BFloat16 result) [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertToChecked(BFloat16 value, [MaybeNullWhen(false)] out TOther result) { - // In order to reduce overall code duplication and improve the inlinabilty of these - // methods for the corelib types we have `ConvertFrom` handle the same sign and - // `ConvertTo` handle the opposite sign. However, since there is an uneven split - // between signed and unsigned types, the one that handles unsigned will also - // handle `Decimal`. - // - // That is, `ConvertFrom` for `BFloat16` will handle the other signed types and - // `ConvertTo` will handle the unsigned types. + // `BFloat16` is non-first class type in System.Numerics namespace. + // It should handle all conversions from/to types under System namespace. + if (typeof(TOther) == typeof(sbyte)) + { + sbyte actualResult = checked((sbyte)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(short)) + { + short actualResult = checked((short)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(int)) + { + int actualResult = checked((int)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(long)) + { + long actualResult = checked((long)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(Int128)) + { + Int128 actualResult = checked((Int128)value); + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(nint)) + { + nint actualResult = checked((nint)value); + result = (TOther)(object)actualResult; + return true; + } if (typeof(TOther) == typeof(byte)) { byte actualResult = checked((byte)value); @@ -1627,56 +1668,91 @@ static bool INumberBase.TryConvertToTruncating(BFloat16 value, private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase { - // In order to reduce overall code duplication and improve the inlinabilty of these - // methods for the corelib types we have `ConvertFrom` handle the same sign and - // `ConvertTo` handle the opposite sign. However, since there is an uneven split - // between signed and unsigned types, the one that handles unsigned will also - // handle `Decimal`. - // - // That is, `ConvertFrom` for `BFloat16` will handle the other signed types and - // `ConvertTo` will handle the unsigned types + // `BFloat16` is non-first class type in System.Numerics namespace. + // It should handle all conversions from/to types under System namespace. - if (typeof(TOther) == typeof(byte)) + if (typeof(TOther) == typeof(sbyte)) + { + sbyte actualResult = (value >= sbyte.MaxValue) ? sbyte.MaxValue : + (value <= sbyte.MinValue) ? sbyte.MinValue : (sbyte)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(short)) + { + short actualResult = ((float)value >= short.MaxValue) ? short.MaxValue : + ((float)value <= short.MinValue) ? short.MinValue : (short)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(int)) + { + int actualResult = ((float)value >= int.MaxValue) ? int.MaxValue : + ((float)value <= int.MinValue) ? int.MinValue : (int)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(long)) + { + long actualResult = ((float)value >= long.MaxValue) ? long.MaxValue : + ((float)value <= long.MinValue) ? long.MinValue : (long)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(Int128)) + { + Int128 actualResult = ((float)value >= +170141183460469231731687303715884105727.0f) ? Int128.MaxValue : + ((float)value <= -170141183460469231731687303715884105728.0f) ? Int128.MinValue : (Int128)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(nint)) + { + nint actualResult = ((float)value >= nint.MaxValue) ? nint.MaxValue : + ((float)value <= nint.MinValue) ? nint.MinValue : (nint)value; + result = (TOther)(object)actualResult; + return true; + } + else if (typeof(TOther) == typeof(byte)) { - var actualResult = (value >= byte.MaxValue) ? byte.MaxValue : - (value <= byte.MinValue) ? byte.MinValue : (byte)value; + byte actualResult = ((float)value >= byte.MaxValue) ? byte.MaxValue : + ((float)value <= byte.MinValue) ? byte.MinValue : (byte)value; result = (TOther)(object)actualResult; return true; } else if (typeof(TOther) == typeof(char)) { - char actualResult = (value == PositiveInfinity) ? char.MaxValue : + char actualResult = ((float)value >= char.MaxValue) ? char.MaxValue : (value <= Zero) ? char.MinValue : (char)value; result = (TOther)(object)actualResult; return true; } else if (typeof(TOther) == typeof(decimal)) { - decimal actualResult = (value == PositiveInfinity) ? decimal.MaxValue : - (value == NegativeInfinity) ? decimal.MinValue : + decimal actualResult = ((float)value >= +79228162514264337593543950336.0f) ? decimal.MaxValue : + ((float)value <= -79228162514264337593543950336.0f) ? decimal.MinValue : IsNaN(value) ? 0.0m : (decimal)value; result = (TOther)(object)actualResult; return true; } else if (typeof(TOther) == typeof(ushort)) { - ushort actualResult = (value == PositiveInfinity) ? ushort.MaxValue : + ushort actualResult = ((float)value >= ushort.MaxValue) ? ushort.MaxValue : (value <= Zero) ? ushort.MinValue : (ushort)value; result = (TOther)(object)actualResult; return true; } else if (typeof(TOther) == typeof(uint)) { - uint actualResult = (value == PositiveInfinity) ? uint.MaxValue : + uint actualResult = ((float)value >= uint.MaxValue) ? uint.MaxValue : (value <= Zero) ? uint.MinValue : (uint)value; result = (TOther)(object)actualResult; return true; } else if (typeof(TOther) == typeof(ulong)) { - ulong actualResult = (value == PositiveInfinity) ? ulong.MaxValue : - (value <= Zero) ? ulong.MinValue : - IsNaN(value) ? 0 : (ulong)value; + ulong actualResult = ((float)value >= ulong.MaxValue) ? ulong.MaxValue : + (value <= Zero) ? ulong.MinValue : (ulong)value; result = (TOther)(object)actualResult; return true; } @@ -1689,7 +1765,7 @@ private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] } else if (typeof(TOther) == typeof(nuint)) { - nuint actualResult = (value == PositiveInfinity) ? nuint.MaxValue : + nuint actualResult = ((float)value >= nuint.MaxValue) ? nuint.MaxValue : (value <= Zero) ? nuint.MinValue : (nuint)value; result = (TOther)(object)actualResult; return true; From 8c5f546e0edd6d35bb5f07c9fb52e41b35d12af8 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 01:35:30 +0800 Subject: [PATCH 30/67] Fullfill some formatting --- .../Common/src/System/Number.NumberBuffer.cs | 1 - .../System.Private.CoreLib.Shared.projitems | 1 + .../src/System/Number.Grisu3.cs | 2 +- .../src/System/Numerics/Number.BFloat16.cs | 143 ++++++++++++++++++ 4 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs diff --git a/src/libraries/Common/src/System/Number.NumberBuffer.cs b/src/libraries/Common/src/System/Number.NumberBuffer.cs index 9df0e5c4771ba6..5b4fc7a7564e8f 100644 --- a/src/libraries/Common/src/System/Number.NumberBuffer.cs +++ b/src/libraries/Common/src/System/Number.NumberBuffer.cs @@ -21,7 +21,6 @@ internal static partial class Number internal const int UInt32NumberBufferLength = 10 + 1; // 10 for the longest input: 4,294,967,295 internal const int UInt64NumberBufferLength = 20 + 1; // 20 for the longest input: 18,446,744,073,709,551,615 internal const int UInt128NumberBufferLength = 39 + 1; // 39 for the longest input: 340,282,366,920,938,463,463,374,607,431,768,211,455 - internal const int BFloat16NumberBufferLength = 96 + 1 + 1; // 96 for the longest input + 1 for rounding (+1 for the null terminator) internal unsafe ref struct NumberBuffer { diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index adb9620e6f49f1..88bcc6089c6a0b 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -593,6 +593,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs index 4a746b38cc2c31..8858aa478f4801 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs @@ -16,7 +16,7 @@ internal static partial class Number // The general idea behind Grisu3 is to leverage additional bits and cached powers of ten to generate the correct digits. // The algorithm is imprecise for some numbers. Fortunately, the algorithm itself can determine this scenario and gives us // a result indicating success or failure. We must fallback to a different algorithm for the failing scenario. - internal static class Grisu3 + internal static partial class Grisu3 { private const int CachedPowersDecimalExponentDistance = 8; private const int CachedPowersMinDecimalExponent = -348; diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs new file mode 100644 index 00000000000000..6088571b7994d6 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs @@ -0,0 +1,143 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Numerics; + +namespace System +{ + internal static partial class Number + { + internal const int BFloat16NumberBufferLength = 96 + 1 + 1; // 96 for the longest input + 1 for rounding (+1 for the null terminator) + + // Undetermined values + private const int BFloat16Precision = 5; + private const int BFloat16PrecisionCustomFormat = 5; + + public static string FormatBFloat16(BFloat16 value, string? format, NumberFormatInfo info) + { + var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); + string result = FormatBFloat16(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); + vlb.Dispose(); + return result; + } + + /// Formats the specified value according to the specified format and info. + /// + /// Non-null if an existing string can be returned, in which case the builder will be unmodified. + /// Null if no existing string was returned, in which case the formatted output is in the builder. + /// + private static unsafe string? FormatBFloat16(ref ValueListBuilder vlb, BFloat16 value, ReadOnlySpan format, NumberFormatInfo info) where TChar : unmanaged, IUtfChar + { + Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); + + if (!BFloat16.IsFinite(value)) + { + if (BFloat16.IsNaN(value)) + { + if (typeof(TChar) == typeof(char)) + { + return info.NaNSymbol; + } + else + { + vlb.Append(info.NaNSymbolTChar()); + return null; + } + } + + if (typeof(TChar) == typeof(char)) + { + return BFloat16.IsNegative(value) ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol; + } + else + { + vlb.Append(BFloat16.IsNegative(value) ? info.NegativeInfinitySymbolTChar() : info.PositiveInfinitySymbolTChar()); + return null; + } + } + + char fmt = ParseFormatSpecifier(format, out int precision); + byte* pDigits = stackalloc byte[BFloat16NumberBufferLength]; + + if (fmt == '\0') + { + precision = BFloat16PrecisionCustomFormat; + } + + NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, BFloat16NumberBufferLength); + number.IsNegative = BFloat16.IsNegative(value); + + // We need to track the original precision requested since some formats + // accept values like 0 and others may require additional fixups. + int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(fmt, ref precision, info, out bool isSignificantDigits); + + if ((value != default) && (!isSignificantDigits || !Grisu3.TryRunBFloat16(value, precision, ref number))) + { + Dragon4BFloat16(value, precision, isSignificantDigits, ref number); + } + + number.CheckConsistency(); + + // When the number is known to be roundtrippable (either because we requested it be, or + // because we know we have enough digits to satisfy roundtrippability), we should validate + // that the number actually roundtrips back to the original result. + + Debug.Assert(((precision != -1) && (precision < BFloat16Precision)) || (value._value == NumberToFloat(ref number)._value)); + + if (fmt != 0) + { + if (precision == -1) + { + Debug.Assert((fmt == 'G') || (fmt == 'g') || (fmt == 'R') || (fmt == 'r')); + + // For the roundtrip and general format specifiers, when returning the shortest roundtrippable + // string, we need to update the maximum number of digits to be the greater of number.DigitsCount + // or SinglePrecision. This ensures that we continue returning "pretty" strings for values with + // less digits. One example this fixes is "-60", which would otherwise be formatted as "-6E+01" + // since DigitsCount would be 1 and the formatter would almost immediately switch to scientific notation. + + nMaxDigits = Math.Max(number.DigitsCount, BFloat16Precision); + } + NumberToString(ref vlb, ref number, fmt, nMaxDigits, info); + } + else + { + Debug.Assert(precision == BFloat16PrecisionCustomFormat); + NumberToStringFormat(ref vlb, ref number, format, info); + } + return null; + } + + public static bool TryFormatBFloat16(BFloat16 value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar + { + Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); + + var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); + string? s = FormatBFloat16(ref vlb, value, format, info); + + Debug.Assert(s is null || typeof(TChar) == typeof(char)); + bool success = s != null ? + TryCopyTo(s, destination, out charsWritten) : + vlb.TryCopyTo(destination, out charsWritten); + + vlb.Dispose(); + return success; + } + + public static unsafe void Dragon4BFloat16(BFloat16 value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) + { + throw new NotImplementedException(); + } + + internal static partial class Grisu3 + { + public static bool TryRunBFloat16(BFloat16 value, int requestedDigits, ref NumberBuffer number) + { + throw new NotImplementedException(); + } + } + } +} From 0cb3932d2d5d8038696516b717768e2f788864c4 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 6 Apr 2024 13:05:53 +0800 Subject: [PATCH 31/67] Apply suggestions from code review Co-authored-by: Tanner Gooding --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- .../System.Private.CoreLib/src/System/Numerics/BFloat16.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 88bcc6089c6a0b..db7584876a2d5d 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -593,7 +593,7 @@ - + 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 281324cad05693..db36836c936d54 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -496,7 +496,7 @@ public static explicit operator BFloat16(float value) // Only do rounding for finite numbers if (float.IsFinite(value)) { - uint lower = bits & 0xFFFF; + uint lower = (ushort)bits; // Determine the increment for rounding // When upper is even, midpoint (0x8000) will tie to no increment, which is effectively a decrement of lower uint lowerShift = (~upper) & (lower >> 15) & 1; // Upper is even & lower>=0x8000 (not 0) From 8f70d918f66998b97679900659ede17d62e06582 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 02:20:06 +0800 Subject: [PATCH 32/67] Generic DiyFp --- .../src/System/Number.DiyFp.cs | 24 ++++++++++++++ .../src/System/Number.Formatting.cs | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs index 268bd53695e7da..c910c0bcff874f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs @@ -68,6 +68,21 @@ public static DiyFp CreateAndGetBoundaries(Half value, out DiyFp mMinus, out Diy return result; } + // Computes the two boundaries of value. + // + // The bigger boundary (mPlus) is normalized. + // The lower boundary has the same exponent as mPlus. + // + // Precondition: + // The value encoded by value must be greater than 0. + public static DiyFp CreateAndGetBoundaries(TNumber value, out DiyFp mMinus, out DiyFp mPlus) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + { + var result = Create(value); + result.GetBoundaries(TNumber.DenormalMantissaBits, out mMinus, out mPlus); + return result; + } + public DiyFp(double value) { Debug.Assert(double.IsFinite(value)); @@ -89,6 +104,15 @@ public DiyFp(Half value) f = ExtractFractionAndBiasedExponent(value, out e); } + public static DiyFp Create(TNumber value) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + { + Debug.Assert(TNumber.IsFinite(value)); + Debug.Assert(value > TNumber.Zero); + ulong f = ExtractFractionAndBiasedExponent(value, out int e); + return new DiyFp(f, e); + } + public DiyFp(ulong f, int e) { this.f = f; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index ad75d88cbda7c1..48b0be3be87294 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -2869,5 +2869,38 @@ private static uint ExtractFractionAndBiasedExponent(float value, out int expone return fraction; } + + private static ulong ExtractFractionAndBiasedExponent(TNumber value, out int exponent) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + { + ulong bits = TNumber.FloatToBits(value); + ulong fraction = (bits & TNumber.DenormalMantissaMask); + exponent = ((int)(bits >> TNumber.DenormalMantissaBits) & TNumber.InfinityExponent); + + if (exponent != 0) + { + // For normalized value, + // value = 1.fraction * 2^(exp - ExponentBias) + // = (1 + mantissa / 2^TrailingSignificandLength) * 2^(exp - ExponentBias) + // = (2^TrailingSignificandLength + mantissa) * 2^(exp - ExponentBias - TrailingSignificandLength) + // + // So f = (2^TrailingSignificandLength + mantissa), e = exp - ExponentBias - TrailingSignificandLength; + + fraction |= (1UL << TNumber.DenormalMantissaBits); + exponent -= TNumber.ExponentBias - TNumber.DenormalMantissaBits; + } + else + { + // For denormalized value, + // value = 0.fraction * 2^(MinBinaryExponent) + // = (mantissa / 2^TrailingSignificandLength) * 2^(MinBinaryExponent) + // = mantissa * 2^(MinBinaryExponent - TrailingSignificandLength) + // = mantissa * 2^(MinBinaryExponent - TrailingSignificandLength) + // So f = mantissa, e = MinBinaryExponent - TrailingSignificandLength + exponent = TNumber.MinBinaryExponent - TNumber.DenormalMantissaBits; + } + + return fraction; + } } } From 2458dd8d6e2c229175bbc749e938685eedc93e42 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 02:26:50 +0800 Subject: [PATCH 33/67] Generic Grisu3 --- .../src/System/Number.Grisu3.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs index 4a746b38cc2c31..b4e01cac10a976 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Numerics; namespace System { @@ -423,6 +424,41 @@ public static bool TryRunSingle(float value, int requestedDigits, ref NumberBuff return result; } + public static bool TryRun(TNumber value, int requestedDigits, ref NumberBuffer number) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + { + TNumber v = TNumber.IsNegative(value) ? -value : value; + + Debug.Assert(v > TNumber.Zero); + Debug.Assert(TNumber.IsFinite(v)); + + int length; + int decimalExponent; + bool result; + + if (requestedDigits == -1) + { + DiyFp w = DiyFp.CreateAndGetBoundaries(v, out DiyFp boundaryMinus, out DiyFp boundaryPlus).Normalize(); + result = TryRunShortest(in boundaryMinus, in w, in boundaryPlus, number.Digits, out length, out decimalExponent); + } + else + { + DiyFp w = DiyFp.Create(v).Normalize(); + result = TryRunCounted(in w, requestedDigits, number.Digits, out length, out decimalExponent); + } + + if (result) + { + Debug.Assert((requestedDigits == -1) || (length == requestedDigits)); + + number.Scale = length + decimalExponent; + number.Digits[length] = (byte)('\0'); + number.DigitsCount = length; + } + + return result; + } + // The counted version of Grisu3 only generates requestedDigits number of digits. // This version does not generate the shortest representation, and with enough requested digits 0.1 will at some point print as 0.9999999... // Grisu3 is too imprecise for real halfway cases (1.5 will not work) and therefore the rounding strategy for halfway cases is irrelevant. From a8bb94bf9c2ecc046ff813d7f135867d6c04bd48 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 02:39:39 +0800 Subject: [PATCH 34/67] Generic Dragon4 --- .../src/System/Number.Dragon4.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs index 10fbfcdbee5478..2a50766a9ff439 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs @@ -100,6 +100,37 @@ public static unsafe void Dragon4Single(float value, int cutoffNumber, bool isSi number.DigitsCount = length; } + public static unsafe void Dragon4(TNumber value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + { + TNumber v = TNumber.IsNegative(value) ? -value : value; + + Debug.Assert(v > TNumber.Zero); + Debug.Assert(TNumber.IsFinite(v)); + + ulong mantissa = ExtractFractionAndBiasedExponent(value, out int exponent); + + uint mantissaHighBitIdx; + bool hasUnequalMargins = false; + + if ((mantissa >> TNumber.DenormalMantissaBits) != 0) + { + mantissaHighBitIdx = TNumber.DenormalMantissaBits; + hasUnequalMargins = (mantissa == (1U << TNumber.DenormalMantissaBits)); + } + else + { + Debug.Assert(mantissa != 0); + mantissaHighBitIdx = (uint)BitOperations.Log2(mantissa); + } + + int length = (int)(Dragon4(mantissa, exponent, mantissaHighBitIdx, hasUnequalMargins, cutoffNumber, isSignificantDigits, number.Digits, out int decimalExponent)); + + number.Scale = decimalExponent + 1; + number.Digits[length] = (byte)('\0'); + number.DigitsCount = length; + } + // This is an implementation of the Dragon4 algorithm to convert a binary number in floating-point format to a decimal number in string format. // The function returns the number of digits written to the output buffer and the output is not NUL terminated. // From 96449145071872f1b816940f583a874ff1697089 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 13:40:33 +0800 Subject: [PATCH 35/67] Add MaxRoundTripDigits to MaxPrecisionCustomFormat to FormatInfo --- .../System.Private.CoreLib/src/System/Double.cs | 4 ++++ .../System.Private.CoreLib/src/System/Half.cs | 4 ++++ .../src/System/Number.Parsing.cs | 12 ++++++++++++ .../System.Private.CoreLib/src/System/Single.cs | 4 ++++ 4 files changed, 24 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 71d73546bc1364..442d5b303efbfa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -2300,6 +2300,10 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ulong IBinaryFloatParseAndFormatInfo.FloatToBits(double value) => BitConverter.DoubleToUInt64Bits(value); + static int IBinaryFloatParseAndFormatInfo.MaxRoundTripDigits => 17; + + static int IBinaryFloatParseAndFormatInfo.MaxPrecisionCustomFormat => 15; + // // Helpers // diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index adc7df07932f7f..73ca82c0c934d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -2362,5 +2362,9 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static Half IBinaryFloatParseAndFormatInfo.BitsToFloat(ulong bits) => BitConverter.UInt16BitsToHalf((ushort)(bits)); static ulong IBinaryFloatParseAndFormatInfo.FloatToBits(Half value) => BitConverter.HalfToUInt16Bits(value); + + static int IBinaryFloatParseAndFormatInfo.MaxRoundTripDigits => 5; + + static int IBinaryFloatParseAndFormatInfo.MaxPrecisionCustomFormat => 5; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index 852b979492c2d5..263f60ad0ba10f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -85,6 +85,18 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract TSelf BitsToFloat(ulong bits); static abstract ulong FloatToBits(TSelf value); + + // Maximum number of digits required to guarantee that any given floating point + // number can roundtrip. Some numbers may require less, but none will require more. + static abstract int MaxRoundTripDigits { get; } + + // SinglePrecisionCustomFormat and DoublePrecisionCustomFormat are used to ensure that + // custom format strings return the same string as in previous releases when the format + // would return x digits or less (where x is the value of the corresponding constant). + // In order to support more digits, we would need to update ParseFormatSpecifier to pre-parse + // the format and determine exactly how many digits are being requested and whether they + // represent "significant digits" or "digits after the decimal point". + static abstract int MaxPrecisionCustomFormat { get; } } internal static partial class Number diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 9cc7c6b56c0adf..87606cbd61424c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -2180,6 +2180,10 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static ulong IBinaryFloatParseAndFormatInfo.FloatToBits(float value) => BitConverter.SingleToUInt32Bits(value); + static int IBinaryFloatParseAndFormatInfo.MaxRoundTripDigits => 9; + + static int IBinaryFloatParseAndFormatInfo.MaxPrecisionCustomFormat => 7; + // // Helpers // From a29db5cee02c39c5288b8ec7d4f538ca9ebaac1c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 13:40:40 +0800 Subject: [PATCH 36/67] Generic FormatFloat --- .../src/System/Number.Formatting.cs | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index 48b0be3be87294..e378d85921b81e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -848,6 +848,122 @@ public static bool TryFormatHalf(Half value, ReadOnlySpan format, N return success; } + public static string FormatFloat(TNumber value, string? format, NumberFormatInfo info) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + { + var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); + string result = FormatFloat(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); + vlb.Dispose(); + return result; + } + + /// Formats the specified value according to the specified format and info. + /// + /// Non-null if an existing string can be returned, in which case the builder will be unmodified. + /// Null if no existing string was returned, in which case the formatted output is in the builder. + /// + private static unsafe string? FormatFloat(ref ValueListBuilder vlb, TNumber value, ReadOnlySpan format, NumberFormatInfo info) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + where TChar : unmanaged, IUtfChar + { + Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); + + if (!TNumber.IsFinite(value)) + { + if (TNumber.IsNaN(value)) + { + if (typeof(TChar) == typeof(char)) + { + return info.NaNSymbol; + } + else + { + vlb.Append(info.NaNSymbolTChar()); + return null; + } + } + + if (typeof(TChar) == typeof(char)) + { + return TNumber.IsNegative(value) ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol; + } + else + { + vlb.Append(TNumber.IsNegative(value) ? info.NegativeInfinitySymbolTChar() : info.PositiveInfinitySymbolTChar()); + return null; + } + } + + char fmt = ParseFormatSpecifier(format, out int precision); + byte* pDigits = stackalloc byte[TNumber.NumberBufferLength]; + + if (fmt == '\0') + { + precision = TNumber.MaxPrecisionCustomFormat; + } + + NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, TNumber.NumberBufferLength); + number.IsNegative = TNumber.IsNegative(value); + + // We need to track the original precision requested since some formats + // accept values like 0 and others may require additional fixups. + int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(fmt, ref precision, info, out bool isSignificantDigits); + + if ((value != default) && (!isSignificantDigits || !Grisu3.TryRun(value, precision, ref number))) + { + Dragon4(value, precision, isSignificantDigits, ref number); + } + + number.CheckConsistency(); + + // When the number is known to be roundtrippable (either because we requested it be, or + // because we know we have enough digits to satisfy roundtrippability), we should validate + // that the number actually roundtrips back to the original result. + + Debug.Assert(((precision != -1) && (precision < TNumber.MaxRoundTripDigits)) || (TNumber.FloatToBits(value) == TNumber.FloatToBits(NumberToFloat(ref number)))); + + if (fmt != 0) + { + if (precision == -1) + { + Debug.Assert((fmt == 'G') || (fmt == 'g') || (fmt == 'R') || (fmt == 'r')); + + // For the roundtrip and general format specifiers, when returning the shortest roundtrippable + // string, we need to update the maximum number of digits to be the greater of number.DigitsCount + // or SinglePrecision. This ensures that we continue returning "pretty" strings for values with + // less digits. One example this fixes is "-60", which would otherwise be formatted as "-6E+01" + // since DigitsCount would be 1 and the formatter would almost immediately switch to scientific notation. + + nMaxDigits = Math.Max(number.DigitsCount, TNumber.MaxRoundTripDigits); + } + NumberToString(ref vlb, ref number, fmt, nMaxDigits, info); + } + else + { + Debug.Assert(precision == TNumber.MaxPrecisionCustomFormat); + NumberToStringFormat(ref vlb, ref number, format, info); + } + return null; + } + + public static bool TryFormatFloat(TNumber value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + where TChar : unmanaged, IUtfChar + { + Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); + + var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); + string? s = FormatFloat(ref vlb, value, format, info); + + Debug.Assert(s is null || typeof(TChar) == typeof(char)); + bool success = s != null ? + TryCopyTo(s, destination, out charsWritten) : + vlb.TryCopyTo(destination, out charsWritten); + + vlb.Dispose(); + return success; + } + private static bool TryCopyTo(string source, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar { Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); From a8a8a49076a59e6167bb5c8f42725e83bcfe6164 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 25 Feb 2024 15:37:13 +0800 Subject: [PATCH 37/67] Adapt with existing FP types --- .../src/System/Double.cs | 12 +- .../System.Private.CoreLib/src/System/Half.cs | 12 +- .../src/System/Number.DiyFp.cs | 67 ---- .../src/System/Number.Dragon4.cs | 90 ----- .../src/System/Number.Formatting.cs | 362 +----------------- .../src/System/Number.Grisu3.cs | 103 ----- .../src/System/Single.cs | 12 +- 7 files changed, 25 insertions(+), 633 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 442d5b303efbfa..9a69c2d6e448b2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -354,33 +354,33 @@ public override int GetHashCode() public override string ToString() { - return Number.FormatDouble(m_value, null, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(m_value, null, NumberFormatInfo.CurrentInfo); } public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) { - return Number.FormatDouble(m_value, format, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(m_value, format, NumberFormatInfo.CurrentInfo); } public string ToString(IFormatProvider? provider) { - return Number.FormatDouble(m_value, null, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(m_value, null, NumberFormatInfo.GetInstance(provider)); } public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) { - return Number.FormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(m_value, format, NumberFormatInfo.GetInstance(provider)); } public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); + return Number.TryFormatFloat(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); } /// public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); + return Number.TryFormatFloat(m_value, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); } public static double Parse(string s) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null); diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 73ca82c0c934d0..fcac21f18eb909 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -505,7 +505,7 @@ public override int GetHashCode() /// public override string ToString() { - return Number.FormatHalf(this, null, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(this, null, NumberFormatInfo.CurrentInfo); } /// @@ -513,7 +513,7 @@ public override string ToString() /// public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) { - return Number.FormatHalf(this, format, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(this, format, NumberFormatInfo.CurrentInfo); } /// @@ -521,7 +521,7 @@ public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] strin /// public string ToString(IFormatProvider? provider) { - return Number.FormatHalf(this, null, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(this, null, NumberFormatInfo.GetInstance(provider)); } /// @@ -529,7 +529,7 @@ public string ToString(IFormatProvider? provider) /// public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) { - return Number.FormatHalf(this, format, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(this, format, NumberFormatInfo.GetInstance(provider)); } /// @@ -542,13 +542,13 @@ public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] strin /// public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatHalf(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); + return Number.TryFormatFloat(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); } /// public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatHalf(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); + return Number.TryFormatFloat(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); } // diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs index c910c0bcff874f..49148306fff0f4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DiyFp.cs @@ -17,57 +17,11 @@ internal static partial class Number // DiyFp are not designed to contain special doubles (NaN and Infinity). internal readonly ref struct DiyFp { - public const int DoubleImplicitBitIndex = 52; - public const int SingleImplicitBitIndex = 23; - public const int HalfImplicitBitIndex = 10; - public const int SignificandSize = 64; public readonly ulong f; public readonly int e; - // Computes the two boundaries of value. - // - // The bigger boundary (mPlus) is normalized. - // The lower boundary has the same exponent as mPlus. - // - // Precondition: - // The value encoded by value must be greater than 0. - public static DiyFp CreateAndGetBoundaries(double value, out DiyFp mMinus, out DiyFp mPlus) - { - var result = new DiyFp(value); - result.GetBoundaries(DoubleImplicitBitIndex, out mMinus, out mPlus); - return result; - } - - // Computes the two boundaries of value. - // - // The bigger boundary (mPlus) is normalized. - // The lower boundary has the same exponent as mPlus. - // - // Precondition: - // The value encoded by value must be greater than 0. - public static DiyFp CreateAndGetBoundaries(float value, out DiyFp mMinus, out DiyFp mPlus) - { - var result = new DiyFp(value); - result.GetBoundaries(SingleImplicitBitIndex, out mMinus, out mPlus); - return result; - } - - // Computes the two boundaries of value. - // - // The bigger boundary (mPlus) is normalized. - // The lower boundary has the same exponent as mPlus. - // - // Precondition: - // The value encoded by value must be greater than 0. - public static DiyFp CreateAndGetBoundaries(Half value, out DiyFp mMinus, out DiyFp mPlus) - { - var result = new DiyFp(value); - result.GetBoundaries(HalfImplicitBitIndex, out mMinus, out mPlus); - return result; - } - // Computes the two boundaries of value. // // The bigger boundary (mPlus) is normalized. @@ -83,27 +37,6 @@ public static DiyFp CreateAndGetBoundaries(TNumber value, out DiyFp mMi return result; } - public DiyFp(double value) - { - Debug.Assert(double.IsFinite(value)); - Debug.Assert(value > 0.0); - f = ExtractFractionAndBiasedExponent(value, out e); - } - - public DiyFp(float value) - { - Debug.Assert(float.IsFinite(value)); - Debug.Assert(value > 0.0f); - f = ExtractFractionAndBiasedExponent(value, out e); - } - - public DiyFp(Half value) - { - Debug.Assert(Half.IsFinite(value)); - Debug.Assert((float)value > 0.0f); - f = ExtractFractionAndBiasedExponent(value, out e); - } - public static DiyFp Create(TNumber value) where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs index 2a50766a9ff439..038fdb23947ddc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Dragon4.cs @@ -10,96 +10,6 @@ namespace System // The backing algorithm and the proofs behind it are described in more detail here: https://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf internal static partial class Number { - public static void Dragon4Double(double value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) - { - double v = double.IsNegative(value) ? -value : value; - - Debug.Assert(v > 0); - Debug.Assert(double.IsFinite(v)); - - ulong mantissa = ExtractFractionAndBiasedExponent(value, out int exponent); - - uint mantissaHighBitIdx; - bool hasUnequalMargins = false; - - if ((mantissa >> DiyFp.DoubleImplicitBitIndex) != 0) - { - mantissaHighBitIdx = DiyFp.DoubleImplicitBitIndex; - hasUnequalMargins = (mantissa == (1UL << DiyFp.DoubleImplicitBitIndex)); - } - else - { - Debug.Assert(mantissa != 0); - mantissaHighBitIdx = (uint)BitOperations.Log2(mantissa); - } - - int length = (int)(Dragon4(mantissa, exponent, mantissaHighBitIdx, hasUnequalMargins, cutoffNumber, isSignificantDigits, number.Digits, out int decimalExponent)); - - number.Scale = decimalExponent + 1; - number.Digits[length] = (byte)('\0'); - number.DigitsCount = length; - } - - public static unsafe void Dragon4Half(Half value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) - { - Half v = Half.IsNegative(value) ? Half.Negate(value) : value; - - Debug.Assert((double)v > 0.0); - Debug.Assert(Half.IsFinite(v)); - - ushort mantissa = ExtractFractionAndBiasedExponent(value, out int exponent); - - uint mantissaHighBitIdx; - bool hasUnequalMargins = false; - - if ((mantissa >> DiyFp.HalfImplicitBitIndex) != 0) - { - mantissaHighBitIdx = DiyFp.HalfImplicitBitIndex; - hasUnequalMargins = (mantissa == (1U << DiyFp.HalfImplicitBitIndex)); - } - else - { - Debug.Assert(mantissa != 0); - mantissaHighBitIdx = (uint)BitOperations.Log2(mantissa); - } - - int length = (int)(Dragon4(mantissa, exponent, mantissaHighBitIdx, hasUnequalMargins, cutoffNumber, isSignificantDigits, number.Digits, out int decimalExponent)); - - number.Scale = decimalExponent + 1; - number.Digits[length] = (byte)('\0'); - number.DigitsCount = length; - } - - public static unsafe void Dragon4Single(float value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) - { - float v = float.IsNegative(value) ? -value : value; - - Debug.Assert(v > 0); - Debug.Assert(float.IsFinite(v)); - - uint mantissa = ExtractFractionAndBiasedExponent(value, out int exponent); - - uint mantissaHighBitIdx; - bool hasUnequalMargins = false; - - if ((mantissa >> DiyFp.SingleImplicitBitIndex) != 0) - { - mantissaHighBitIdx = DiyFp.SingleImplicitBitIndex; - hasUnequalMargins = (mantissa == (1U << DiyFp.SingleImplicitBitIndex)); - } - else - { - Debug.Assert(mantissa != 0); - mantissaHighBitIdx = (uint)BitOperations.Log2(mantissa); - } - - int length = (int)(Dragon4(mantissa, exponent, mantissaHighBitIdx, hasUnequalMargins, cutoffNumber, isSignificantDigits, number.Digits, out int decimalExponent)); - - number.Scale = decimalExponent + 1; - number.Digits[length] = (byte)('\0'); - number.DigitsCount = length; - } - public static unsafe void Dragon4(TNumber value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index e378d85921b81e..e1b743f142ddea 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -252,23 +252,6 @@ internal static partial class Number { internal const int DecimalPrecision = 29; // Decimal.DecCalc also uses this value - // SinglePrecision and DoublePrecision represent the maximum number of digits required - // to guarantee that any given Single or Double can roundtrip. Some numbers may require - // less, but none will require more. - private const int HalfPrecision = 5; - private const int SinglePrecision = 9; - private const int DoublePrecision = 17; - - // SinglePrecisionCustomFormat and DoublePrecisionCustomFormat are used to ensure that - // custom format strings return the same string as in previous releases when the format - // would return x digits or less (where x is the value of the corresponding constant). - // In order to support more digits, we would need to update ParseFormatSpecifier to pre-parse - // the format and determine exactly how many digits are being requested and whether they - // represent "significant digits" or "digits after the decimal point". - private const int HalfPrecisionCustomFormat = 5; - private const int SinglePrecisionCustomFormat = 7; - private const int DoublePrecisionCustomFormat = 15; - private const int CharStackBufferSize = 32; /// The non-inclusive upper bound of . @@ -396,28 +379,6 @@ internal static unsafe void DecimalToNumber(scoped ref decimal d, ref NumberBuff number.CheckConsistency(); } - public static string FormatDouble(double value, string? format, NumberFormatInfo info) - { - var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); - string result = FormatDouble(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); - vlb.Dispose(); - return result; - } - - public static bool TryFormatDouble(double value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar - { - var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); - string? s = FormatDouble(ref vlb, value, format, info); - - Debug.Assert(s is null || typeof(TChar) == typeof(char)); - bool success = s != null ? - TryCopyTo(s, destination, out charsWritten) : - vlb.TryCopyTo(destination, out charsWritten); - - vlb.Dispose(); - return success; - } - private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int precision, NumberFormatInfo info, out bool isSignificantDigits) { if (fmt == 0) @@ -539,305 +500,23 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci return maxDigits; } - /// Formats the specified value according to the specified format and info. - /// - /// Non-null if an existing string can be returned, in which case the builder will be unmodified. - /// Null if no existing string was returned, in which case the formatted output is in the builder. - /// - private static unsafe string? FormatDouble(ref ValueListBuilder vlb, double value, ReadOnlySpan format, NumberFormatInfo info) where TChar : unmanaged, IUtfChar - { - if (!double.IsFinite(value)) - { - if (double.IsNaN(value)) - { - if (typeof(TChar) == typeof(char)) - { - return info.NaNSymbol; - } - else - { - vlb.Append(info.NaNSymbolTChar()); - return null; - } - } - - if (typeof(TChar) == typeof(char)) - { - return double.IsNegative(value) ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol; - } - else - { - vlb.Append(double.IsNegative(value) ? info.NegativeInfinitySymbolTChar() : info.PositiveInfinitySymbolTChar()); - return null; - } - } - - char fmt = ParseFormatSpecifier(format, out int precision); - byte* pDigits = stackalloc byte[DoubleNumberBufferLength]; - - if (fmt == '\0') - { - // For back-compat we currently specially treat the precision for custom - // format specifiers. The constant has more details as to why. - precision = DoublePrecisionCustomFormat; - } - - NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, DoubleNumberBufferLength); - number.IsNegative = double.IsNegative(value); - - // We need to track the original precision requested since some formats - // accept values like 0 and others may require additional fixups. - int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(fmt, ref precision, info, out bool isSignificantDigits); - - if ((value != 0.0) && (!isSignificantDigits || !Grisu3.TryRunDouble(value, precision, ref number))) - { - Dragon4Double(value, precision, isSignificantDigits, ref number); - } - - number.CheckConsistency(); - - // When the number is known to be roundtrippable (either because we requested it be, or - // because we know we have enough digits to satisfy roundtrippability), we should validate - // that the number actually roundtrips back to the original result. - - Debug.Assert(((precision != -1) && (precision < DoublePrecision)) || (BitConverter.DoubleToInt64Bits(value) == BitConverter.DoubleToInt64Bits(NumberToFloat(ref number)))); - - if (fmt != 0) - { - if (precision == -1) - { - Debug.Assert((fmt == 'G') || (fmt == 'g') || (fmt == 'R') || (fmt == 'r')); - - // For the roundtrip and general format specifiers, when returning the shortest roundtrippable - // string, we need to update the maximum number of digits to be the greater of number.DigitsCount - // or DoublePrecision. This ensures that we continue returning "pretty" strings for values with - // less digits. One example this fixes is "-60", which would otherwise be formatted as "-6E+01" - // since DigitsCount would be 1 and the formatter would almost immediately switch to scientific notation. - - nMaxDigits = Math.Max(number.DigitsCount, DoublePrecision); - } - NumberToString(ref vlb, ref number, fmt, nMaxDigits, info); - } - else - { - Debug.Assert(precision == DoublePrecisionCustomFormat); - NumberToStringFormat(ref vlb, ref number, format, info); - } - return null; - } - - public static string FormatSingle(float value, string? format, NumberFormatInfo info) - { - var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); - string result = FormatSingle(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); - vlb.Dispose(); - return result; - } - - public static bool TryFormatSingle(float value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar - { - var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); - string? s = FormatSingle(ref vlb, value, format, info); - - Debug.Assert(s is null || typeof(TChar) == typeof(char)); - bool success = s != null ? - TryCopyTo(s, destination, out charsWritten) : - vlb.TryCopyTo(destination, out charsWritten); - - vlb.Dispose(); - return success; - } - - /// Formats the specified value according to the specified format and info. - /// - /// Non-null if an existing string can be returned, in which case the builder will be unmodified. - /// Null if no existing string was returned, in which case the formatted output is in the builder. - /// - private static unsafe string? FormatSingle(ref ValueListBuilder vlb, float value, ReadOnlySpan format, NumberFormatInfo info) where TChar : unmanaged, IUtfChar - { - Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); - - if (!float.IsFinite(value)) - { - if (float.IsNaN(value)) - { - if (typeof(TChar) == typeof(char)) - { - return info.NaNSymbol; - } - else - { - vlb.Append(info.NaNSymbolTChar()); - return null; - } - } - - if (typeof(TChar) == typeof(char)) - { - return float.IsNegative(value) ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol; - } - else - { - vlb.Append(float.IsNegative(value) ? info.NegativeInfinitySymbolTChar() : info.PositiveInfinitySymbolTChar()); - return null; - } - } - - char fmt = ParseFormatSpecifier(format, out int precision); - byte* pDigits = stackalloc byte[SingleNumberBufferLength]; - - if (fmt == '\0') - { - // For back-compat we currently specially treat the precision for custom - // format specifiers. The constant has more details as to why. - precision = SinglePrecisionCustomFormat; - } - - NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, SingleNumberBufferLength); - number.IsNegative = float.IsNegative(value); - - // We need to track the original precision requested since some formats - // accept values like 0 and others may require additional fixups. - int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(fmt, ref precision, info, out bool isSignificantDigits); - - if ((value != default) && (!isSignificantDigits || !Grisu3.TryRunSingle(value, precision, ref number))) - { - Dragon4Single(value, precision, isSignificantDigits, ref number); - } - - number.CheckConsistency(); - - // When the number is known to be roundtrippable (either because we requested it be, or - // because we know we have enough digits to satisfy roundtrippability), we should validate - // that the number actually roundtrips back to the original result. - - Debug.Assert(((precision != -1) && (precision < SinglePrecision)) || (BitConverter.SingleToInt32Bits(value) == BitConverter.SingleToInt32Bits(NumberToFloat(ref number)))); - - if (fmt != 0) - { - if (precision == -1) - { - Debug.Assert((fmt == 'G') || (fmt == 'g') || (fmt == 'R') || (fmt == 'r')); - - // For the roundtrip and general format specifiers, when returning the shortest roundtrippable - // string, we need to update the maximum number of digits to be the greater of number.DigitsCount - // or SinglePrecision. This ensures that we continue returning "pretty" strings for values with - // less digits. One example this fixes is "-60", which would otherwise be formatted as "-6E+01" - // since DigitsCount would be 1 and the formatter would almost immediately switch to scientific notation. - - nMaxDigits = Math.Max(number.DigitsCount, SinglePrecision); - } - NumberToString(ref vlb, ref number, fmt, nMaxDigits, info); - } - else - { - Debug.Assert(precision == SinglePrecisionCustomFormat); - NumberToStringFormat(ref vlb, ref number, format, info); - } - return null; - } - - public static string FormatHalf(Half value, string? format, NumberFormatInfo info) + public static string FormatFloat(TNumber value, string? format, NumberFormatInfo info) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo { var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); - string result = FormatHalf(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); + string result = FormatFloat(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); vlb.Dispose(); return result; } - /// Formats the specified value according to the specified format and info. - /// - /// Non-null if an existing string can be returned, in which case the builder will be unmodified. - /// Null if no existing string was returned, in which case the formatted output is in the builder. - /// - private static unsafe string? FormatHalf(ref ValueListBuilder vlb, Half value, ReadOnlySpan format, NumberFormatInfo info) where TChar : unmanaged, IUtfChar - { - Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); - - if (!Half.IsFinite(value)) - { - if (Half.IsNaN(value)) - { - if (typeof(TChar) == typeof(char)) - { - return info.NaNSymbol; - } - else - { - vlb.Append(info.NaNSymbolTChar()); - return null; - } - } - - if (typeof(TChar) == typeof(char)) - { - return Half.IsNegative(value) ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol; - } - else - { - vlb.Append(Half.IsNegative(value) ? info.NegativeInfinitySymbolTChar() : info.PositiveInfinitySymbolTChar()); - return null; - } - } - - char fmt = ParseFormatSpecifier(format, out int precision); - byte* pDigits = stackalloc byte[HalfNumberBufferLength]; - - if (fmt == '\0') - { - precision = HalfPrecisionCustomFormat; - } - - NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, HalfNumberBufferLength); - number.IsNegative = Half.IsNegative(value); - - // We need to track the original precision requested since some formats - // accept values like 0 and others may require additional fixups. - int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(fmt, ref precision, info, out bool isSignificantDigits); - - if ((value != default) && (!isSignificantDigits || !Grisu3.TryRunHalf(value, precision, ref number))) - { - Dragon4Half(value, precision, isSignificantDigits, ref number); - } - - number.CheckConsistency(); - - // When the number is known to be roundtrippable (either because we requested it be, or - // because we know we have enough digits to satisfy roundtrippability), we should validate - // that the number actually roundtrips back to the original result. - - Debug.Assert(((precision != -1) && (precision < HalfPrecision)) || (BitConverter.HalfToInt16Bits(value) == BitConverter.HalfToInt16Bits(NumberToFloat(ref number)))); - - if (fmt != 0) - { - if (precision == -1) - { - Debug.Assert((fmt == 'G') || (fmt == 'g') || (fmt == 'R') || (fmt == 'r')); - - // For the roundtrip and general format specifiers, when returning the shortest roundtrippable - // string, we need to update the maximum number of digits to be the greater of number.DigitsCount - // or SinglePrecision. This ensures that we continue returning "pretty" strings for values with - // less digits. One example this fixes is "-60", which would otherwise be formatted as "-6E+01" - // since DigitsCount would be 1 and the formatter would almost immediately switch to scientific notation. - - nMaxDigits = Math.Max(number.DigitsCount, HalfPrecision); - } - NumberToString(ref vlb, ref number, fmt, nMaxDigits, info); - } - else - { - Debug.Assert(precision == HalfPrecisionCustomFormat); - NumberToStringFormat(ref vlb, ref number, format, info); - } - return null; - } - - public static bool TryFormatHalf(Half value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar + public static bool TryFormatFloat(TNumber value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) + where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo + where TChar : unmanaged, IUtfChar { Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); - string? s = FormatHalf(ref vlb, value, format, info); + string? s = FormatFloat(ref vlb, value, format, info); Debug.Assert(s is null || typeof(TChar) == typeof(char)); bool success = s != null ? @@ -848,15 +527,6 @@ public static bool TryFormatHalf(Half value, ReadOnlySpan format, N return success; } - public static string FormatFloat(TNumber value, string? format, NumberFormatInfo info) - where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo - { - var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); - string result = FormatFloat(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); - vlb.Dispose(); - return result; - } - /// Formats the specified value according to the specified format and info. /// /// Non-null if an existing string can be returned, in which case the builder will be unmodified. @@ -946,24 +616,6 @@ public static string FormatFloat(TNumber value, string? format, NumberF return null; } - public static bool TryFormatFloat(TNumber value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) - where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo - where TChar : unmanaged, IUtfChar - { - Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); - - var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); - string? s = FormatFloat(ref vlb, value, format, info); - - Debug.Assert(s is null || typeof(TChar) == typeof(char)); - bool success = s != null ? - TryCopyTo(s, destination, out charsWritten) : - vlb.TryCopyTo(destination, out charsWritten); - - vlb.Dispose(); - return success; - } - private static bool TryCopyTo(string source, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar { Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs index b4e01cac10a976..e4a25b9b5939c6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; -using System.Numerics; namespace System { @@ -322,108 +321,6 @@ internal static class Grisu3 1000000000, // 10^9 ]; - public static bool TryRunDouble(double value, int requestedDigits, ref NumberBuffer number) - { - double v = double.IsNegative(value) ? -value : value; - - Debug.Assert(v > 0); - Debug.Assert(double.IsFinite(v)); - - int length; - int decimalExponent; - bool result; - - if (requestedDigits == -1) - { - DiyFp w = DiyFp.CreateAndGetBoundaries(v, out DiyFp boundaryMinus, out DiyFp boundaryPlus).Normalize(); - result = TryRunShortest(in boundaryMinus, in w, in boundaryPlus, number.Digits, out length, out decimalExponent); - } - else - { - DiyFp w = new DiyFp(v).Normalize(); - result = TryRunCounted(in w, requestedDigits, number.Digits, out length, out decimalExponent); - } - - if (result) - { - Debug.Assert((requestedDigits == -1) || (length == requestedDigits)); - - number.Scale = length + decimalExponent; - number.Digits[length] = (byte)('\0'); - number.DigitsCount = length; - } - - return result; - } - - public static bool TryRunHalf(Half value, int requestedDigits, ref NumberBuffer number) - { - Half v = Half.IsNegative(value) ? Half.Negate(value) : value; - - Debug.Assert((double)v > 0); - Debug.Assert(Half.IsFinite(v)); - - int length; - int decimalExponent; - bool result; - - if (requestedDigits == -1) - { - DiyFp w = DiyFp.CreateAndGetBoundaries(v, out DiyFp boundaryMinus, out DiyFp boundaryPlus).Normalize(); - result = TryRunShortest(in boundaryMinus, in w, in boundaryPlus, number.Digits, out length, out decimalExponent); - } - else - { - DiyFp w = new DiyFp(v).Normalize(); - result = TryRunCounted(in w, requestedDigits, number.Digits, out length, out decimalExponent); - } - - if (result) - { - Debug.Assert((requestedDigits == -1) || (length == requestedDigits)); - - number.Scale = length + decimalExponent; - number.Digits[length] = (byte)('\0'); - number.DigitsCount = length; - } - - return result; - } - - public static bool TryRunSingle(float value, int requestedDigits, ref NumberBuffer number) - { - float v = float.IsNegative(value) ? -value : value; - - Debug.Assert(v > 0); - Debug.Assert(float.IsFinite(v)); - - int length; - int decimalExponent; - bool result; - - if (requestedDigits == -1) - { - DiyFp w = DiyFp.CreateAndGetBoundaries(v, out DiyFp boundaryMinus, out DiyFp boundaryPlus).Normalize(); - result = TryRunShortest(in boundaryMinus, in w, in boundaryPlus, number.Digits, out length, out decimalExponent); - } - else - { - DiyFp w = new DiyFp(v).Normalize(); - result = TryRunCounted(in w, requestedDigits, number.Digits, out length, out decimalExponent); - } - - if (result) - { - Debug.Assert((requestedDigits == -1) || (length == requestedDigits)); - - number.Scale = length + decimalExponent; - number.Digits[length] = (byte)('\0'); - number.DigitsCount = length; - } - - return result; - } - public static bool TryRun(TNumber value, int requestedDigits, ref NumberBuffer number) where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo { diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 87606cbd61424c..2ce82e07764670 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -349,33 +349,33 @@ public override int GetHashCode() public override string ToString() { - return Number.FormatSingle(m_value, null, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(m_value, null, NumberFormatInfo.CurrentInfo); } public string ToString(IFormatProvider? provider) { - return Number.FormatSingle(m_value, null, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(m_value, null, NumberFormatInfo.GetInstance(provider)); } public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) { - return Number.FormatSingle(m_value, format, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(m_value, format, NumberFormatInfo.CurrentInfo); } public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) { - return Number.FormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(m_value, format, NumberFormatInfo.GetInstance(provider)); } public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); + return Number.TryFormatFloat(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); } /// public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatSingle(m_value, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); + return Number.TryFormatFloat(m_value, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); } // Parses a float from a String in the given style. If From f1582e70df97b4841463244eb97f39f6ea3692ba Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 6 Apr 2024 17:23:51 +0800 Subject: [PATCH 38/67] Adapt formatting traits --- .../src/System/Number.Parsing.cs | 70 ++++++++++++++----- .../src/System/Numerics/BFloat16.cs | 4 ++ 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index d0902cffef527b..e5caa915534a24 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -50,7 +50,10 @@ internal interface IBinaryIntegerParseAndFormatInfo : IBinaryInteger : IBinaryFloatingPointIeee754, IMinMaxValue where TSelf : unmanaged, IBinaryFloatParseAndFormatInfo { - static abstract int NumberBufferLength { get; } // Ceiling(Log10(5^(Abs(MinBinaryExponent) - 1))) + NormalMantissaBits + 1 + 1 + /// + /// Ceiling(Log10(5^(Abs(MinBinaryExponent) - 1))) + NormalMantissaBits + 1 + 1 + /// + static abstract int NumberBufferLength { get; } static abstract ulong ZeroBits { get; } static abstract ulong InfinityBits { get; } @@ -61,8 +64,15 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract int MinBinaryExponent { get; } static abstract int MaxBinaryExponent { get; } - static abstract int MinDecimalExponent { get; } // Floor(Log10(Epsilon)) - static abstract int MaxDecimalExponent { get; } // Ceiling(Log10(MaxValue)) + /// + /// Floor(Log10(Epsilon)) + /// + static abstract int MinDecimalExponent { get; } + + /// + /// Ceiling(Log10(MaxValue)) + /// + static abstract int MaxDecimalExponent { get; } static abstract int ExponentBias { get; } static abstract ushort ExponentBits { get; } @@ -73,29 +83,53 @@ internal interface IBinaryFloatParseAndFormatInfo : IBinaryFloatingPointI static abstract ushort NormalMantissaBits { get; } static abstract ushort DenormalMantissaBits { get; } - static abstract int MinFastFloatDecimalExponent { get; } // Ceiling(Log10(2^(MinBinaryExponent - 1 - DenormalMantissaBits - 64))) - static abstract int MaxFastFloatDecimalExponent { get; } // MaxDecimalExponent - 1 - - static abstract int MinExponentRoundToEven { get; } // -Floor(Log5(2^(64 - NormalMantissaBits))) - static abstract int MaxExponentRoundToEven { get; } // Floor(Log5(2^(NormalMantissaBits + 1))) - - static abstract int MaxExponentFastPath { get; } // Max(n) when 10^n can be precisely represented + /// + /// Ceiling(Log10(2^(MinBinaryExponent - 1 - DenormalMantissaBits - 64))) + /// + static abstract int MinFastFloatDecimalExponent { get; } + + /// + /// MaxDecimalExponent - 1 + /// + static abstract int MaxFastFloatDecimalExponent { get; } + + /// + /// -Floor(Log5(2^(64 - NormalMantissaBits))) + /// + static abstract int MinExponentRoundToEven { get; } + + /// + /// Floor(Log5(2^(NormalMantissaBits + 1))) + /// + static abstract int MaxExponentRoundToEven { get; } + + /// + /// Max(n) when 10^n can be precisely represented + /// + static abstract int MaxExponentFastPath { get; } static abstract ulong MaxMantissaFastPath { get; } static abstract TSelf BitsToFloat(ulong bits); static abstract ulong FloatToBits(TSelf value); - // Maximum number of digits required to guarantee that any given floating point - // number can roundtrip. Some numbers may require less, but none will require more. + /// + /// Maximum number of digits required to guarantee that any given floating point + /// number can roundtrip. Some numbers may require less, but none will require more. + /// + /// + /// Ceiling(Log10(2^NormalMantissaBits)) + 1 + /// static abstract int MaxRoundTripDigits { get; } - // SinglePrecisionCustomFormat and DoublePrecisionCustomFormat are used to ensure that - // custom format strings return the same string as in previous releases when the format - // would return x digits or less (where x is the value of the corresponding constant). - // In order to support more digits, we would need to update ParseFormatSpecifier to pre-parse - // the format and determine exactly how many digits are being requested and whether they - // represent "significant digits" or "digits after the decimal point". + /// + /// MaxPrecisionCustomFormat is used to ensure that + /// custom format strings return the same string as in previous releases when the format + /// would return x digits or less (where x is the value of the corresponding constant). + /// In order to support more digits, we would need to update ParseFormatSpecifier to pre-parse + /// the format and determine exactly how many digits are being requested and whether they + /// represent "significant digits" or "digits after the decimal point". + /// static abstract int MaxPrecisionCustomFormat { get; } } 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 db36836c936d54..3c329a6478fb96 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1977,6 +1977,10 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo static int IBinaryFloatParseAndFormatInfo.MaxExponentFastPath => 3; static ulong IBinaryFloatParseAndFormatInfo.MaxMantissaFastPath => 2UL << TrailingSignificandLength; + static int IBinaryFloatParseAndFormatInfo.MaxRoundTripDigits => 4; + + static int IBinaryFloatParseAndFormatInfo.MaxPrecisionCustomFormat => 4; + static BFloat16 IBinaryFloatParseAndFormatInfo.BitsToFloat(ulong bits) => new BFloat16((ushort)(bits)); static ulong IBinaryFloatParseAndFormatInfo.FloatToBits(BFloat16 value) => value._value; From eace3a68bed2bc5fe1c6f42c660dab3ed2dacf30 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 6 Apr 2024 17:32:27 +0800 Subject: [PATCH 39/67] Use generic format and delete Number.BFloat16 --- .../System.Private.CoreLib.Shared.projitems | 1 - .../src/System/Numerics/BFloat16.cs | 14 +- .../src/System/Numerics/Number.BFloat16.cs | 143 ------------------ 3 files changed, 7 insertions(+), 151 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 8cb77cbba7bfb9..5a2f71d175a4c9 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -595,7 +595,6 @@ - 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 3c329a6478fb96..a657ff553f94ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -65,7 +65,7 @@ public readonly struct BFloat16 private const ushort PositiveInfinityBits = 0x7F80; private const ushort NegativeInfinityBits = 0xFF80; - private const ushort PositiveQNaNBits = 0x7FC0; + // private const ushort PositiveQNaNBits = 0x7FC0; private const ushort NegativeQNaNBits = 0xFFC0; private const ushort MinValueBits = 0xFF7F; @@ -399,7 +399,7 @@ public int CompareTo(object? obj) /// public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) { - return Number.FormatBFloat16(this, format, NumberFormatInfo.CurrentInfo); + return Number.FormatFloat(this, format, NumberFormatInfo.CurrentInfo); } /// @@ -407,7 +407,7 @@ public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] strin /// public string ToString(IFormatProvider? provider) { - return Number.FormatBFloat16(this, null, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(this, null, NumberFormatInfo.GetInstance(provider)); } /// @@ -415,7 +415,7 @@ public string ToString(IFormatProvider? provider) /// public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) { - return Number.FormatBFloat16(this, format, NumberFormatInfo.GetInstance(provider)); + return Number.FormatFloat(this, format, NumberFormatInfo.GetInstance(provider)); } /// @@ -428,13 +428,13 @@ public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] strin /// public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatBFloat16(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); + return Number.TryFormatFloat(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten); } /// public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) { - return Number.TryFormatBFloat16(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); + return Number.TryFormatFloat(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten); } // @@ -1945,7 +1945,7 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo // IBinaryFloatParseAndFormatInfo // - static int IBinaryFloatParseAndFormatInfo.NumberBufferLength => Number.BFloat16NumberBufferLength; + static int IBinaryFloatParseAndFormatInfo.NumberBufferLength => 96 + 1 + 1; // 96 for the longest input + 1 for rounding (+1 for the null terminator) static ulong IBinaryFloatParseAndFormatInfo.ZeroBits => 0; static ulong IBinaryFloatParseAndFormatInfo.InfinityBits => PositiveInfinityBits; diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs deleted file mode 100644 index 6088571b7994d6..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Number.BFloat16.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Numerics; - -namespace System -{ - internal static partial class Number - { - internal const int BFloat16NumberBufferLength = 96 + 1 + 1; // 96 for the longest input + 1 for rounding (+1 for the null terminator) - - // Undetermined values - private const int BFloat16Precision = 5; - private const int BFloat16PrecisionCustomFormat = 5; - - public static string FormatBFloat16(BFloat16 value, string? format, NumberFormatInfo info) - { - var vlb = new ValueListBuilder(stackalloc char[CharStackBufferSize]); - string result = FormatBFloat16(ref vlb, value, format, info) ?? vlb.AsSpan().ToString(); - vlb.Dispose(); - return result; - } - - /// Formats the specified value according to the specified format and info. - /// - /// Non-null if an existing string can be returned, in which case the builder will be unmodified. - /// Null if no existing string was returned, in which case the formatted output is in the builder. - /// - private static unsafe string? FormatBFloat16(ref ValueListBuilder vlb, BFloat16 value, ReadOnlySpan format, NumberFormatInfo info) where TChar : unmanaged, IUtfChar - { - Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); - - if (!BFloat16.IsFinite(value)) - { - if (BFloat16.IsNaN(value)) - { - if (typeof(TChar) == typeof(char)) - { - return info.NaNSymbol; - } - else - { - vlb.Append(info.NaNSymbolTChar()); - return null; - } - } - - if (typeof(TChar) == typeof(char)) - { - return BFloat16.IsNegative(value) ? info.NegativeInfinitySymbol : info.PositiveInfinitySymbol; - } - else - { - vlb.Append(BFloat16.IsNegative(value) ? info.NegativeInfinitySymbolTChar() : info.PositiveInfinitySymbolTChar()); - return null; - } - } - - char fmt = ParseFormatSpecifier(format, out int precision); - byte* pDigits = stackalloc byte[BFloat16NumberBufferLength]; - - if (fmt == '\0') - { - precision = BFloat16PrecisionCustomFormat; - } - - NumberBuffer number = new NumberBuffer(NumberBufferKind.FloatingPoint, pDigits, BFloat16NumberBufferLength); - number.IsNegative = BFloat16.IsNegative(value); - - // We need to track the original precision requested since some formats - // accept values like 0 and others may require additional fixups. - int nMaxDigits = GetFloatingPointMaxDigitsAndPrecision(fmt, ref precision, info, out bool isSignificantDigits); - - if ((value != default) && (!isSignificantDigits || !Grisu3.TryRunBFloat16(value, precision, ref number))) - { - Dragon4BFloat16(value, precision, isSignificantDigits, ref number); - } - - number.CheckConsistency(); - - // When the number is known to be roundtrippable (either because we requested it be, or - // because we know we have enough digits to satisfy roundtrippability), we should validate - // that the number actually roundtrips back to the original result. - - Debug.Assert(((precision != -1) && (precision < BFloat16Precision)) || (value._value == NumberToFloat(ref number)._value)); - - if (fmt != 0) - { - if (precision == -1) - { - Debug.Assert((fmt == 'G') || (fmt == 'g') || (fmt == 'R') || (fmt == 'r')); - - // For the roundtrip and general format specifiers, when returning the shortest roundtrippable - // string, we need to update the maximum number of digits to be the greater of number.DigitsCount - // or SinglePrecision. This ensures that we continue returning "pretty" strings for values with - // less digits. One example this fixes is "-60", which would otherwise be formatted as "-6E+01" - // since DigitsCount would be 1 and the formatter would almost immediately switch to scientific notation. - - nMaxDigits = Math.Max(number.DigitsCount, BFloat16Precision); - } - NumberToString(ref vlb, ref number, fmt, nMaxDigits, info); - } - else - { - Debug.Assert(precision == BFloat16PrecisionCustomFormat); - NumberToStringFormat(ref vlb, ref number, format, info); - } - return null; - } - - public static bool TryFormatBFloat16(BFloat16 value, ReadOnlySpan format, NumberFormatInfo info, Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar - { - Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); - - var vlb = new ValueListBuilder(stackalloc TChar[CharStackBufferSize]); - string? s = FormatBFloat16(ref vlb, value, format, info); - - Debug.Assert(s is null || typeof(TChar) == typeof(char)); - bool success = s != null ? - TryCopyTo(s, destination, out charsWritten) : - vlb.TryCopyTo(destination, out charsWritten); - - vlb.Dispose(); - return success; - } - - public static unsafe void Dragon4BFloat16(BFloat16 value, int cutoffNumber, bool isSignificantDigits, ref NumberBuffer number) - { - throw new NotImplementedException(); - } - - internal static partial class Grisu3 - { - public static bool TryRunBFloat16(BFloat16 value, int requestedDigits, ref NumberBuffer number) - { - throw new NotImplementedException(); - } - } - } -} From abd1e8028adb972115fc242752d8d7266120c83c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 6 Apr 2024 17:41:08 +0800 Subject: [PATCH 40/67] Update ref source --- .../System.Runtime/ref/System.Runtime.cs | 217 +++++++++++++++++- 1 file changed, 216 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 333d12a916dffb..81cf5c7b12371a 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10613,28 +10613,243 @@ public static void HtmlEncode(string? value, System.IO.TextWriter output) { } } namespace System.Numerics { - public readonly partial struct BFloat16 : System.IComparable, System.IComparable, System.IEquatable + public readonly partial struct BFloat16 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.IUtf8SpanFormattable, System.IUtf8SpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IBinaryFloatingPointIeee754, System.Numerics.IBinaryNumber, System.Numerics.IBitwiseOperators, System.Numerics.IComparisonOperators, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IFloatingPointIeee754, System.Numerics.IHyperbolicFunctions, System.Numerics.IIncrementOperators, System.Numerics.ILogarithmicFunctions, System.Numerics.IMinMaxValue, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IPowerFunctions, System.Numerics.IRootFunctions, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.ITrigonometricFunctions, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators { private readonly int _dummyPrimitive; + public static System.Numerics.BFloat16 E { get { throw null; } } public static System.Numerics.BFloat16 Epsilon { get { throw null; } } public static System.Numerics.BFloat16 MaxValue { get { throw null; } } public static System.Numerics.BFloat16 MinValue { get { throw null; } } + public static System.Numerics.BFloat16 MultiplicativeIdentity { get { throw null; } } + public static System.Numerics.BFloat16 NaN { get { throw null; } } + public static System.Numerics.BFloat16 NegativeInfinity { get { throw null; } } + public static System.Numerics.BFloat16 NegativeOne { get { throw null; } } + public static System.Numerics.BFloat16 NegativeZero { get { throw null; } } + public static System.Numerics.BFloat16 One { get { throw null; } } + public static System.Numerics.BFloat16 Pi { get { throw null; } } + public static System.Numerics.BFloat16 PositiveInfinity { get { throw null; } } + static System.Numerics.BFloat16 System.Numerics.IAdditiveIdentity.AdditiveIdentity { get { throw null; } } + static System.Numerics.BFloat16 System.Numerics.IBinaryNumber.AllBitsSet { get { throw null; } } + static int System.Numerics.INumberBase.Radix { get { throw null; } } + public static System.Numerics.BFloat16 Tau { get { throw null; } } + public static System.Numerics.BFloat16 Zero { get { throw null; } } + public static System.Numerics.BFloat16 Abs(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 Acos(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Acosh(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 AcosPi(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Asin(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Asinh(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 AsinPi(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Atan(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Atan2(System.Numerics.BFloat16 y, System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Atan2Pi(System.Numerics.BFloat16 y, System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Atanh(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 AtanPi(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 BitDecrement(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 BitIncrement(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Cbrt(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Ceiling(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Clamp(System.Numerics.BFloat16 value, System.Numerics.BFloat16 min, System.Numerics.BFloat16 max) { throw null; } public int CompareTo(System.Numerics.BFloat16 other) { throw null; } public int CompareTo(object? obj) { throw null; } + public static System.Numerics.BFloat16 CopySign(System.Numerics.BFloat16 value, System.Numerics.BFloat16 sign) { throw null; } + public static System.Numerics.BFloat16 Cos(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Cosh(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 CosPi(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 CreateChecked(TOther value) where TOther : System.Numerics.INumberBase { throw null; } + public static System.Numerics.BFloat16 CreateSaturating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } + public static System.Numerics.BFloat16 CreateTruncating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } + public static System.Numerics.BFloat16 DegreesToRadians(System.Numerics.BFloat16 degrees) { throw null; } public bool Equals(System.Numerics.BFloat16 other) { throw null; } public override bool Equals(object? obj) { throw null; } + public static System.Numerics.BFloat16 Exp(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Exp10(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Exp10M1(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Exp2(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Exp2M1(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 ExpM1(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Floor(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 FusedMultiplyAdd(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right, System.Numerics.BFloat16 addend) { throw null; } public override int GetHashCode() { throw null; } + public static System.Numerics.BFloat16 Hypot(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 Ieee754Remainder(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static int ILogB(System.Numerics.BFloat16 x) { throw null; } + public static bool IsEvenInteger(System.Numerics.BFloat16 value) { throw null; } + public static bool IsFinite(System.Numerics.BFloat16 value) { throw null; } + public static bool IsInfinity(System.Numerics.BFloat16 value) { throw null; } + public static bool IsInteger(System.Numerics.BFloat16 value) { throw null; } + public static bool IsNaN(System.Numerics.BFloat16 value) { throw null; } + public static bool IsNegative(System.Numerics.BFloat16 value) { throw null; } + public static bool IsNegativeInfinity(System.Numerics.BFloat16 value) { throw null; } + public static bool IsNormal(System.Numerics.BFloat16 value) { throw null; } + public static bool IsOddInteger(System.Numerics.BFloat16 value) { throw null; } + public static bool IsPositive(System.Numerics.BFloat16 value) { throw null; } + public static bool IsPositiveInfinity(System.Numerics.BFloat16 value) { throw null; } + public static bool IsPow2(System.Numerics.BFloat16 value) { throw null; } + public static bool IsRealNumber(System.Numerics.BFloat16 value) { throw null; } + public static bool IsSubnormal(System.Numerics.BFloat16 value) { throw null; } + public static bool IsZero(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 Lerp(System.Numerics.BFloat16 value1, System.Numerics.BFloat16 value2, System.Numerics.BFloat16 amount) { throw null; } + public static System.Numerics.BFloat16 Log(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Log(System.Numerics.BFloat16 x, System.Numerics.BFloat16 newBase) { throw null; } + public static System.Numerics.BFloat16 Log10(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Log10P1(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Log2(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 Log2P1(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 LogP1(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Max(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 MaxMagnitude(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 MaxMagnitudeNumber(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 MaxNumber(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 Min(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 MinMagnitude(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 MinMagnitudeNumber(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 MinNumber(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 operator +(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static explicit operator checked byte (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator checked char (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator checked short (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator checked int (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator checked long (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator checked System.Int128 (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator checked nint (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked sbyte (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked ushort (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked uint (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked ulong (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked System.UInt128 (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked nuint (System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 operator --(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 operator /(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } public static bool operator ==(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static explicit operator System.Numerics.BFloat16 (char value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (decimal value) { throw null; } public static explicit operator System.Numerics.BFloat16 (double value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (System.Half value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (System.Int128 value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (short value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (int value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (long value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (nint value) { throw null; } + public static explicit operator byte (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator char (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator decimal (System.Numerics.BFloat16 value) { throw null; } public static explicit operator double (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator System.Int128 (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator short (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator int (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator long (System.Numerics.BFloat16 value) { throw null; } + public static explicit operator nint (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator sbyte (System.Numerics.BFloat16 value) { throw null; } public static explicit operator float (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.UInt128 (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ushort (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator uint (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ulong (System.Numerics.BFloat16 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator nuint (System.Numerics.BFloat16 value) { throw null; } public static explicit operator System.Numerics.BFloat16 (float value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.BFloat16 (System.UInt128 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.BFloat16 (ushort value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.BFloat16 (uint value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.BFloat16 (ulong value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.BFloat16 (nuint value) { throw null; } public static bool operator >(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } public static bool operator >=(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static implicit operator System.Numerics.BFloat16 (byte value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Numerics.BFloat16 (sbyte value) { throw null; } + public static System.Numerics.BFloat16 operator ++(System.Numerics.BFloat16 value) { throw null; } public static bool operator !=(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } public static bool operator <(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } public static bool operator <=(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static System.Numerics.BFloat16 operator %(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static System.Numerics.BFloat16 operator *(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static System.Numerics.BFloat16 operator -(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + public static System.Numerics.BFloat16 operator -(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 operator +(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 Parse(System.ReadOnlySpan utf8Text, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.AllowTrailingWhite, System.IFormatProvider? provider = null) { throw null; } + public static System.Numerics.BFloat16 Parse(System.ReadOnlySpan utf8Text, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.BFloat16 Parse(System.ReadOnlySpan s, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.AllowTrailingWhite, System.IFormatProvider? provider = null) { throw null; } + public static System.Numerics.BFloat16 Parse(System.ReadOnlySpan s, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.BFloat16 Parse(string s) { throw null; } + public static System.Numerics.BFloat16 Parse(string s, System.Globalization.NumberStyles style) { throw null; } + public static System.Numerics.BFloat16 Parse(string s, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.AllowTrailingWhite, System.IFormatProvider? provider = null) { throw null; } + public static System.Numerics.BFloat16 Parse(string s, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.BFloat16 Pow(System.Numerics.BFloat16 x, System.Numerics.BFloat16 y) { throw null; } + public static System.Numerics.BFloat16 RadiansToDegrees(System.Numerics.BFloat16 radians) { throw null; } + public static System.Numerics.BFloat16 ReciprocalEstimate(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 ReciprocalSqrtEstimate(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 RootN(System.Numerics.BFloat16 x, int n) { throw null; } + public static System.Numerics.BFloat16 Round(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Round(System.Numerics.BFloat16 x, int digits) { throw null; } + public static System.Numerics.BFloat16 Round(System.Numerics.BFloat16 x, int digits, System.MidpointRounding mode) { throw null; } + public static System.Numerics.BFloat16 Round(System.Numerics.BFloat16 x, System.MidpointRounding mode) { throw null; } + public static System.Numerics.BFloat16 ScaleB(System.Numerics.BFloat16 x, int n) { throw null; } + public static int Sign(System.Numerics.BFloat16 value) { throw null; } + public static System.Numerics.BFloat16 Sin(System.Numerics.BFloat16 x) { throw null; } + public static (System.Numerics.BFloat16 Sin, System.Numerics.BFloat16 Cos) SinCos(System.Numerics.BFloat16 x) { throw null; } + public static (System.Numerics.BFloat16 SinPi, System.Numerics.BFloat16 CosPi) SinCosPi(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Sinh(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 SinPi(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Sqrt(System.Numerics.BFloat16 x) { throw null; } + static System.Numerics.BFloat16 System.Numerics.IBitwiseOperators.operator &(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + static System.Numerics.BFloat16 System.Numerics.IBitwiseOperators.operator |(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + static System.Numerics.BFloat16 System.Numerics.IBitwiseOperators.operator ^(System.Numerics.BFloat16 left, System.Numerics.BFloat16 right) { throw null; } + static System.Numerics.BFloat16 System.Numerics.IBitwiseOperators.operator ~(System.Numerics.BFloat16 value) { throw null; } + int System.Numerics.IFloatingPoint.GetExponentByteCount() { throw null; } + int System.Numerics.IFloatingPoint.GetExponentShortestBitLength() { throw null; } + int System.Numerics.IFloatingPoint.GetSignificandBitLength() { throw null; } + int System.Numerics.IFloatingPoint.GetSignificandByteCount() { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteExponentBigEndian(System.Span destination, out int bytesWritten) { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteExponentLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteSignificandBigEndian(System.Span destination, out int bytesWritten) { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteSignificandLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + static bool System.Numerics.INumberBase.IsCanonical(System.Numerics.BFloat16 value) { throw null; } + static bool System.Numerics.INumberBase.IsComplexNumber(System.Numerics.BFloat16 value) { throw null; } + static bool System.Numerics.INumberBase.IsImaginaryNumber(System.Numerics.BFloat16 value) { throw null; } + static bool System.Numerics.INumberBase.IsZero(System.Numerics.BFloat16 value) { throw null; } + static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Numerics.BFloat16 result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Numerics.BFloat16 result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Numerics.BFloat16 result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToChecked(System.Numerics.BFloat16 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToSaturating(System.Numerics.BFloat16 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToTruncating(System.Numerics.BFloat16 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } + public static System.Numerics.BFloat16 Tan(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 Tanh(System.Numerics.BFloat16 x) { throw null; } + public static System.Numerics.BFloat16 TanPi(System.Numerics.BFloat16 x) { throw null; } public override string ToString() { throw null; } + public string ToString(System.IFormatProvider? provider) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.BFloat16 Truncate(System.Numerics.BFloat16 x) { throw null; } + public bool TryFormat(System.Span utf8Destination, out int bytesWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } + public bool TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } + public static bool TryParse(System.ReadOnlySpan utf8Text, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan utf8Text, System.IFormatProvider? provider, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan utf8Text, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, out System.Numerics.BFloat16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Numerics.BFloat16 result) { throw null; } } public static partial class BitOperations { From e8012c98c48a5baa4a8711b57f43e39f9d443818 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 3 May 2024 22:03:10 +0800 Subject: [PATCH 41/67] Enable constant value tests --- .../System/Numerics/BFloat16Tests.cs | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) 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 1c4811807134d9..3281fded0a4d1a 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 @@ -13,14 +13,30 @@ public class BFloat16Tests private static BFloat16 UInt16BitsToBFloat16(ushort value) => Unsafe.BitCast(value); - private static bool IsNaN(BFloat16 value) => float.IsNaN(BitConverter.Int32BitsToSingle(BFloat16ToUInt16Bits(value) << 16)); - [Fact] public static void Epsilon() { Assert.Equal(0x0001u, BFloat16ToUInt16Bits(BFloat16.Epsilon)); } + [Fact] + public static void PositiveInfinity() + { + Assert.Equal(0x7F80u, BFloat16ToUInt16Bits(BFloat16.PositiveInfinity)); + } + + [Fact] + public static void NegativeInfinity() + { + Assert.Equal(0xFF80u, BFloat16ToUInt16Bits(BFloat16.NegativeInfinity)); + } + + [Fact] + public static void NaN() + { + Assert.Equal(0xFFC0u, BFloat16ToUInt16Bits(BFloat16.NaN)); + } + [Fact] public static void MinValue() { @@ -60,18 +76,18 @@ public static IEnumerable CompareTo_TestData() yield return new object[] { BFloat16.Epsilon, UInt16BitsToBFloat16(0x8001), 1 }; yield return new object[] { BFloat16.MaxValue, UInt16BitsToBFloat16(0x0000), 1 }; yield return new object[] { BFloat16.MaxValue, BFloat16.Epsilon, 1 }; - // yield return new object[] { BFloat16.MaxValue, BFloat16.PositiveInfinity, -1 }; + yield return new object[] { BFloat16.MaxValue, BFloat16.PositiveInfinity, -1 }; yield return new object[] { BFloat16.MinValue, BFloat16.MaxValue, -1 }; - // yield return new object[] { BFloat16.MaxValue, BFloat16.NaN, 1 }; - // yield return new object[] { BFloat16.NaN, BFloat16.NaN, 0 }; - // yield return new object[] { BFloat16.NaN, UInt16BitsToBFloat16(0x0000), -1 }; + yield return new object[] { BFloat16.MaxValue, BFloat16.NaN, 1 }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, 0 }; + yield return new object[] { BFloat16.NaN, UInt16BitsToBFloat16(0x0000), -1 }; yield return new object[] { BFloat16.MaxValue, null, 1 }; - // yield return new object[] { BFloat16.MinValue, BFloat16.NegativeInfinity, 1 }; - // yield return new object[] { BFloat16.NegativeInfinity, BFloat16.MinValue, -1 }; - // yield return new object[] { UInt16BitsToBFloat16(0x8000), BFloat16.NegativeInfinity, 1 }; // Negative zero - // yield return new object[] { BFloat16.NegativeInfinity, UInt16BitsToBFloat16(0x8000), -1 }; // Negative zero - // yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NegativeInfinity, 0 }; - // yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0 }; + yield return new object[] { BFloat16.MinValue, BFloat16.NegativeInfinity, 1 }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.MinValue, -1 }; + yield return new object[] { UInt16BitsToBFloat16(0x8000), BFloat16.NegativeInfinity, 1 }; // Negative zero + yield return new object[] { BFloat16.NegativeInfinity, UInt16BitsToBFloat16(0x8000), -1 }; // Negative zero + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NegativeInfinity, 0 }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0 }; yield return new object[] { (BFloat16)(-180f), (BFloat16)(-180f), 0 }; yield return new object[] { (BFloat16)(180f), (BFloat16)(180f), 0 }; yield return new object[] { (BFloat16)(-180f), (BFloat16)(180f), -1 }; @@ -87,7 +103,7 @@ public static void CompareTo(BFloat16 value, object obj, int expected) { Assert.Equal(expected, Math.Sign(value.CompareTo(other))); - if (IsNaN(value) || IsNaN(other)) + if (BFloat16.IsNaN(value) || BFloat16.IsNaN(other)) { Assert.False(value >= other); Assert.False(value > other); @@ -150,10 +166,10 @@ public static IEnumerable ExplicitConversion_ToSingle_TestData() (UInt16BitsToBFloat16(0b1_01111011_1001101), -0.10009765625f), // -0.1ish (UInt16BitsToBFloat16(0b0_10000100_0101000), 42f), // 42 (UInt16BitsToBFloat16(0b1_10000100_0101000), -42f), // -42 - // (BFloat16.PositiveInfinity, float.PositiveInfinity), // PosInfinity - // (BFloat16.NegativeInfinity, float.NegativeInfinity), // NegInfinity + (BFloat16.PositiveInfinity, float.PositiveInfinity), // PosInfinity + (BFloat16.NegativeInfinity, float.NegativeInfinity), // NegInfinity (UInt16BitsToBFloat16(0b0_11111111_1000000), BitConverter.UInt32BitsToSingle(0x7FC00000)), // Positive Quiet NaN - // (BFloat16.NaN, float.NaN), // Negative Quiet NaN + (BFloat16.NaN, float.NaN), // Negative Quiet NaN (UInt16BitsToBFloat16(0b0_11111111_1010101), BitConverter.UInt32BitsToSingle(0x7FD50000)), // Positive Signalling NaN - Should preserve payload (UInt16BitsToBFloat16(0b1_11111111_1010101), BitConverter.UInt32BitsToSingle(0xFFD50000)), // Negative Signalling NaN - Should preserve payload (BFloat16.Epsilon, BitConverter.UInt32BitsToSingle(0x00010000)), // PosEpsilon = 9.1835E-41 @@ -202,9 +218,9 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() (-MathF.E, UInt16BitsToBFloat16(0b1_10000000_0101110)), // -2.71875 (float.MaxValue, UInt16BitsToBFloat16(0b0_11111111_0000000)), // Overflow (float.MinValue, UInt16BitsToBFloat16(0b1_11111111_0000000)), // Overflow - //(float.PositiveInfinity, BFloat16.PositiveInfinity), // Overflow - //(float.NegativeInfinity, BFloat16.NegativeInfinity), // Overflow - //(float.NaN, BFloat16.NaN), // Quiet Negative NaN + (float.PositiveInfinity, BFloat16.PositiveInfinity), // Overflow + (float.NegativeInfinity, BFloat16.NegativeInfinity), // Overflow + (float.NaN, BFloat16.NaN), // Quiet Negative NaN (BitConverter.UInt32BitsToSingle(0x7FC00000), UInt16BitsToBFloat16(0b0_11111111_1000000)), // Quiet Positive NaN (BitConverter.UInt32BitsToSingle(0xFFD55555), UInt16BitsToBFloat16(0b1_11111111_1010101)), // Signalling Negative NaN (BitConverter.UInt32BitsToSingle(0x7FD55555), UInt16BitsToBFloat16(0b0_11111111_1010101)), // Signalling Positive NaN From f711f8db5ab1117b30a6f1a9b6ba6547f5088f82 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 3 May 2024 22:07:15 +0800 Subject: [PATCH 42/67] IsFinite/IsNaN --- .../System/Numerics/BFloat16Tests.cs | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) 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 3281fded0a4d1a..b63d12ba38906c 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 @@ -56,6 +56,95 @@ public static void Ctor_Empty() Assert.Equal(0x0000, BFloat16ToUInt16Bits(value)); } + public static IEnumerable IsFinite_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, false }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, true }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8400), true }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x83FF), true }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), true }; // Max Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8000), true }; // Negative Zero + yield return new object[] { BFloat16.NaN, false }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), true }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, true }; // Min Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x03FF), true }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0400), true }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, true }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsFinite_TestData))] + public static void IsFinite(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsFinite(value)); + } + + public static IEnumerable IsInfinity_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, true }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, false }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), false }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), false }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), false }; // Max Negative Subnormal (Negative Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x8000), false }; // Negative Zero + yield return new object[] { BFloat16.NaN, false }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, false }; // Min Positive Subnormal (Positive Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x007F), false }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), false }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, false }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, true }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsInfinity_TestData))] + public static void IsInfinity(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsInfinity(value)); + } + + public static IEnumerable IsNaN_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, false }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, false }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), false }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), false }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), false }; // Max Negative Subnormal (Negative Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x8000), false }; // Negative Zero + yield return new object[] { BFloat16.NaN, true }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, false }; // Min Positive Subnormal (Positive Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x007F), false }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), false }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, false }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsNaN_TestData))] + public static void IsNaN(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsNaN(value)); + } + + public static IEnumerable IsNegative_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, true }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, true }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), true }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), true }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), true }; // Max Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8000), true }; // Negative Zero + yield return new object[] { BFloat16.NaN, true }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, false }; // Min Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x007F), false }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), false }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, false }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity + } + public static IEnumerable CompareTo_ThrowsArgumentException_TestData() { yield return new object[] { "a" }; From 08168fff1a93eaae316a1d1ff14d9e725232bf8e Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 3 May 2024 22:09:54 +0800 Subject: [PATCH 43/67] IsPositive/IsNegative/IsSubnormal --- .../System/Numerics/BFloat16Tests.cs | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) 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 b63d12ba38906c..f7e92a01446999 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 @@ -145,6 +145,109 @@ public static IEnumerable IsNegative_TestData() yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity } + [Theory] + [MemberData(nameof(IsNegative_TestData))] + public static void IsNegative(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsNegative(value)); + } + + public static IEnumerable IsNegativeInfinity_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, true }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, false }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), false }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), false }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), false }; // Max Negative Subnormal (Negative Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x8000), false }; // Negative Zero + yield return new object[] { BFloat16.NaN, false }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, false }; // Min Positive Subnormal (Positive Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x007F), false }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), false }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, false }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsNegativeInfinity_TestData))] + public static void IsNegativeInfinity(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsNegativeInfinity(value)); + } + + public static IEnumerable IsNormal_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, false }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, true }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), true }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), false }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), false }; // Max Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8000), false }; // Negative Zero + yield return new object[] { BFloat16.NaN, false }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, false }; // Min Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x007F), false }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), true }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, true }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsNormal_TestData))] + public static void IsNormal(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsNormal(value)); + } + + public static IEnumerable IsPositiveInfinity_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, false }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, false }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), false }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), false }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), false }; // Max Negative Subnormal (Negative Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x8000), false }; // Negative Zero + yield return new object[] { BFloat16.NaN, false }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, false }; // Min Positive Subnormal (Positive Epsilon) + yield return new object[] { UInt16BitsToBFloat16(0x007F), false }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), false }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, false }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, true }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsPositiveInfinity_TestData))] + public static void IsPositiveInfinity(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsPositiveInfinity(value)); + } + + public static IEnumerable IsSubnormal_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, false }; // Negative Infinity + yield return new object[] { BFloat16.MinValue, false }; // Min Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x8080), false }; // Max Negative Normal + yield return new object[] { UInt16BitsToBFloat16(0x807F), true }; // Min Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8001), true }; // Max Negative Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x8000), false }; // Negative Zero + yield return new object[] { BFloat16.NaN, false }; // NaN + yield return new object[] { UInt16BitsToBFloat16(0x0000), false }; // Positive Zero + yield return new object[] { BFloat16.Epsilon, true }; // Min Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x007F), true }; // Max Positive Subnormal + yield return new object[] { UInt16BitsToBFloat16(0x0080), false }; // Min Positive Normal + yield return new object[] { BFloat16.MaxValue, false }; // Max Positive Normal + yield return new object[] { BFloat16.PositiveInfinity, false }; // Positive Infinity + } + + [Theory] + [MemberData(nameof(IsSubnormal_TestData))] + public static void IsSubnormal(BFloat16 value, bool expected) + { + Assert.Equal(expected, BFloat16.IsSubnormal(value)); + } + public static IEnumerable CompareTo_ThrowsArgumentException_TestData() { yield return new object[] { "a" }; From d59a8c5fe61832abeb1c91e4f52cf2600438893c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 4 May 2024 01:04:31 +0800 Subject: [PATCH 44/67] ToDouble --- .../src/System/Numerics/BFloat16.cs | 3 +- .../System/Numerics/BFloat16Tests.cs | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) 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 a657ff553f94ca..58d20219d523f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using static System.Reflection.Emit.TypeNameBuilder; namespace System.Numerics { @@ -392,7 +393,7 @@ public int CompareTo(object? obj) /// /// Returns a string representation of the current value. /// - public override string ToString() => ((float)this).ToString(); + public override string ToString() => Number.FormatFloat(this, null, NumberFormatInfo.CurrentInfo); /// /// Returns a string representation of the current value using the specified . 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 f7e92a01446999..7ca93c71b8b310 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 @@ -400,6 +400,62 @@ public static IEnumerable ExplicitConversion_ToSingle_TestData() float f = (float)value; AssertExtensions.Equal(expected, f); } + + public static IEnumerable ExplicitConversion_ToDouble_TestData() + { + (BFloat16 Original, double Expected)[] data = + { + (UInt16BitsToBFloat16(0b0_01111_0000000000), 1d), // 1 + (UInt16BitsToBFloat16(0b1_01111_0000000000), -1d), // -1 + (BFloat16.MaxValue, BitConverter.UInt64BitsToDouble(0x47EFE000_00000000)), // 3.3895314E+38 + (BFloat16.MinValue, BitConverter.UInt64BitsToDouble(0xC7EFE000_00000000)), // -3.3895314E+38 + (UInt16BitsToBFloat16(0b0_01111011_1001101), 0.10009765625d), // 0.1ish + (UInt16BitsToBFloat16(0b1_01111011_1001101), -0.10009765625d), // -0.1ish + (UInt16BitsToBFloat16(0b0_10000100_0101000), 42d), // 42 + (UInt16BitsToBFloat16(0b1_10000100_0101000), -42d), // -42 + (BFloat16.PositiveInfinity, double.PositiveInfinity), // PosInfinity + (BFloat16.NegativeInfinity, double.NegativeInfinity), // NegInfinity + (UInt16BitsToBFloat16(0b0_11111111_1000000), BitConverter.UInt64BitsToDouble(0x7FF80000_00000000)), // Positive Quiet NaN + (BFloat16.NaN, double.NaN), // Negative Quiet NaN + (UInt16BitsToBFloat16(0b0_11111111_1010101), BitConverter.UInt64BitsToDouble(0x7FFAA000_00000000)), // Positive Signalling NaN - Should preserve payload + (UInt16BitsToBFloat16(0b1_11111111_1010101), BitConverter.UInt64BitsToDouble(0xFFFAA000_00000000)), // Negative Signalling NaN - Should preserve payload + (BFloat16.Epsilon, BitConverter.UInt64BitsToDouble(0x37A00000_00000000)), // PosEpsilon = 9.1835E-41 + (UInt16BitsToBFloat16(0), 0d), // 0 + (UInt16BitsToBFloat16(0b1_00000000_0000000), -0d), // -0 + (UInt16BitsToBFloat16(0b0_10000000_1001001), 3.140625d), // 3.140625 + (UInt16BitsToBFloat16(0b1_10000000_1001001), -3.140625d), // -3.140625 + (UInt16BitsToBFloat16(0b0_10000000_0101110), 2.71875d), // 2.71875 + (UInt16BitsToBFloat16(0b1_10000000_0101110), -2.71875d), // -2.71875 + (UInt16BitsToBFloat16(0b0_01111111_1000000), 1.5d), // 1.5 + (UInt16BitsToBFloat16(0b1_01111111_1000000), -1.5d), // -1.5 + (UInt16BitsToBFloat16(0b0_01111111_1000001), 1.5078125d), // 1.5078125 + (UInt16BitsToBFloat16(0b1_01111111_1000001), -1.5078125d), // -1.5078125 + (UInt16BitsToBFloat16(0b0_00000001_0000000), BitConverter.UInt64BitsToDouble(0x3810000000000000)), // smallest normal + (UInt16BitsToBFloat16(0b0_00000000_1111111), BitConverter.UInt64BitsToDouble(0x380FC00000000000)), // largest subnormal + (UInt16BitsToBFloat16(0b0_00000000_1000000), BitConverter.UInt64BitsToDouble(0x3800000000000000)), // middle subnormal + (UInt16BitsToBFloat16(0b0_00000000_0111111), BitConverter.UInt64BitsToDouble(0x37FF800000000000)), // just below middle subnormal + (UInt16BitsToBFloat16(0b0_00000000_0000001), BitConverter.UInt64BitsToDouble(0x37A0000000000000)), // smallest subnormal + (UInt16BitsToBFloat16(0b1_00000000_0000001), BitConverter.UInt64BitsToDouble(0xB7A0000000000000)), // highest negative subnormal + (UInt16BitsToBFloat16(0b1_00000000_0111111), BitConverter.UInt64BitsToDouble(0xB7FF800000000000)), // just above negative middle subnormal + (UInt16BitsToBFloat16(0b1_00000000_1000000), BitConverter.UInt64BitsToDouble(0xB800000000000000)), // negative middle subnormal + (UInt16BitsToBFloat16(0b1_00000000_1111111), BitConverter.UInt64BitsToDouble(0xB80FC00000000000)), // lowest negative subnormal + (UInt16BitsToBFloat16(0b1_00000001_0000000), BitConverter.UInt64BitsToDouble(0xB810000000000000)) // highest negative normal + }; + + foreach ((BFloat16 original, double expected) in data) + { + yield return new object[] { original, expected }; + } + } + + [MemberData(nameof(ExplicitConversion_ToDouble_TestData))] + [Theory] + public static void ExplicitConversion_ToDouble(BFloat16 value, double expected) // Check the underlying bits for verifying NaNs + { + double d = (double)value; + AssertExtensions.Equal(expected, d); + } + public static IEnumerable ExplicitConversion_FromSingle_TestData() { (float, BFloat16)[] data = From a07fe96e6e3089a35876b9df675ab468195b16f5 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 9 Jun 2024 22:21:49 +0800 Subject: [PATCH 45/67] Fix test case --- .../System.Runtime.Tests/System/Numerics/BFloat16Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7ca93c71b8b310..7d71d9f5c0638e 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 @@ -405,8 +405,8 @@ public static IEnumerable ExplicitConversion_ToDouble_TestData() { (BFloat16 Original, double Expected)[] data = { - (UInt16BitsToBFloat16(0b0_01111_0000000000), 1d), // 1 - (UInt16BitsToBFloat16(0b1_01111_0000000000), -1d), // -1 + (UInt16BitsToBFloat16(0b0_01111111_0000000), 1d), // 1 + (UInt16BitsToBFloat16(0b1_01111111_0000000), -1d), // -1 (BFloat16.MaxValue, BitConverter.UInt64BitsToDouble(0x47EFE000_00000000)), // 3.3895314E+38 (BFloat16.MinValue, BitConverter.UInt64BitsToDouble(0xC7EFE000_00000000)), // -3.3895314E+38 (UInt16BitsToBFloat16(0b0_01111011_1001101), 0.10009765625d), // 0.1ish From f9c35d3d59521fbf8f5a259bded3dbbf6fd69e1c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 9 Jun 2024 23:14:17 +0800 Subject: [PATCH 46/67] Add double conversion test --- .../System/Numerics/BFloat16Tests.cs | 86 ++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) 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 7d71d9f5c0638e..df086a55f91f27 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 @@ -525,7 +525,7 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() (BitConverter.UInt32BitsToSingle(0b1_00000000_10000111000000000000001), UInt16BitsToBFloat16(0b1_00000000_1000100)), // neg subnormal - ULP rounds lower, (BitConverter.UInt32BitsToSingle(0b0_00000000_00000000110000000000000), - UInt16BitsToBFloat16(0b0_00000_000000000)), // (BFloat16-precision minimum subnormal / 2) should underflow to zero + UInt16BitsToBFloat16(0b0_00000_000000000)), // (BFloat16 minimum subnormal / 2) should underflow to zero }; foreach ((float original, BFloat16 expected) in data) @@ -541,5 +541,89 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() BFloat16 b16 = (BFloat16)f; AssertExtensions.Equal(BFloat16ToUInt16Bits(expected), BFloat16ToUInt16Bits(b16)); } + + public static IEnumerable ExplicitConversion_FromDouble_TestData() + { + (double, BFloat16)[] data = + { + (Math.PI, UInt16BitsToBFloat16(0b0_10000000_1001001)), // 3.140625 + (Math.E, UInt16BitsToBFloat16(0b0_10000000_0101110)), // 2.71875 + (-Math.PI, UInt16BitsToBFloat16(0b1_10000000_1001001)), // -3.140625 + (-Math.E, UInt16BitsToBFloat16(0b1_10000000_0101110)), // -2.71875 + (double.MaxValue, BFloat16.PositiveInfinity), // Overflow + (double.MinValue, BFloat16.NegativeInfinity), // Overflow + (double.PositiveInfinity, BFloat16.PositiveInfinity), // Overflow + (double.NegativeInfinity, BFloat16.NegativeInfinity), // Overflow + (double.NaN, BFloat16.NaN), // Quiet Negative NaN + (BitConverter.UInt64BitsToDouble(0x7FF80000_00000000), UInt16BitsToBFloat16(0b0_11111111_1000000)), // Quiet Positive NaN + (BitConverter.UInt64BitsToDouble(0xFFFAAAAA_AAAAAAAA), UInt16BitsToBFloat16(0b1_11111111_1010101)), // Signalling Negative NaN + (BitConverter.UInt64BitsToDouble(0x7FFAAAAA_AAAAAAAA), UInt16BitsToBFloat16(0b0_11111111_1010101)), // Signalling Positive NaN + (double.Epsilon, UInt16BitsToBFloat16(0)), // Underflow + (-double.Epsilon, UInt16BitsToBFloat16(0b1_00000000_0000000)), // Underflow (1f, UInt16BitsToBFloat16(0b0_01111111_0000000)), // 1 + (-1d, UInt16BitsToBFloat16(0b1_01111111_0000000)), // -1 + (0d, UInt16BitsToBFloat16(0)), // 0 + (-0d, UInt16BitsToBFloat16(0b1_00000000_0000000)), // -0 + (42d, UInt16BitsToBFloat16(0b0_10000100_0101000)), // 42 + (-42d, UInt16BitsToBFloat16(0b1_10000100_0101000)), // -42 + (0.1d, UInt16BitsToBFloat16(0b0_01111011_1001101)), // 0.10009765625 + (-0.1d, UInt16BitsToBFloat16(0b1_01111011_1001101)), // -0.10009765625 + (1.5d, UInt16BitsToBFloat16(0b0_01111111_1000000)), // 1.5 + (-1.5d, UInt16BitsToBFloat16(0b1_01111111_1000000)), // -1.5 + (1.5078125d, UInt16BitsToBFloat16(0b0_01111111_1000001)), // 1.5078125 + (-1.5078125d, UInt16BitsToBFloat16(0b1_01111111_1000001)), // -1.5078125 + (BitConverter.UInt64BitsToDouble(0x3810000000000000), UInt16BitsToBFloat16(0b0_00000001_0000000)), // smallest normal + (BitConverter.UInt64BitsToDouble(0x380FC00000000000), UInt16BitsToBFloat16(0b0_00000000_1111111)), // largest subnormal + (BitConverter.UInt64BitsToDouble(0x3800000000000000), UInt16BitsToBFloat16(0b0_00000000_1000000)), // middle subnormal + (BitConverter.UInt64BitsToDouble(0x37FF800000000000), UInt16BitsToBFloat16(0b0_00000000_0111111)), // just below middle subnormal + (BitConverter.UInt64BitsToDouble(0x37A0000000000000), UInt16BitsToBFloat16(0b0_00000000_0000001)), // smallest subnormal + (BitConverter.UInt64BitsToDouble(0xB7A0000000000000), UInt16BitsToBFloat16(0b1_00000000_0000001)), // highest negative subnormal + (BitConverter.UInt64BitsToDouble(0xB7FF800000000000), UInt16BitsToBFloat16(0b1_00000000_0111111)), // just above negative middle subnormal + (BitConverter.UInt64BitsToDouble(0xB800000000000000), UInt16BitsToBFloat16(0b1_00000000_1000000)), // negative middle subnormal + (BitConverter.UInt64BitsToDouble(0xB80FC00000000000), UInt16BitsToBFloat16(0b1_00000000_1111111)), // lowest negative subnormal + (BitConverter.UInt64BitsToDouble(0xB810000000000000), UInt16BitsToBFloat16(0b1_00000001_0000000)), // highest negative normal + (BitConverter.UInt64BitsToDouble(0x4090700000000001), + UInt16BitsToBFloat16(0b0_10001001_0000100)), // 1052+ULP rounds up + (BitConverter.UInt64BitsToDouble(0x4090700000000000), + UInt16BitsToBFloat16(0b0_10001001_0000100)), // 1052 rounds to even + (BitConverter.UInt64BitsToDouble(0x40906FFFFFFFFFFF), + UInt16BitsToBFloat16(0b0_10001001_0000011)), // 1052-ULP rounds down + (BitConverter.UInt64BitsToDouble(0x4090500000000000), + UInt16BitsToBFloat16(0b0_10001001_0000010)), // 1044 rounds to even + (BitConverter.UInt64BitsToDouble(0xC0906FFFFFFFFFFF), + UInt16BitsToBFloat16(0b1_10001001_0000011)), // -1052+ULP rounds towards zero + (BitConverter.UInt64BitsToDouble(0xC090700000000000), + UInt16BitsToBFloat16(0b1_10001001_0000100)), // -1052 rounds to even + (BitConverter.UInt64BitsToDouble(0xC090700000000001), + UInt16BitsToBFloat16(0b1_10001001_0000100)), // -1052-ULP rounds away from zero + (BitConverter.UInt64BitsToDouble(0xC090500000000000), + UInt16BitsToBFloat16(0b1_10001001_0000010)), // -1044 rounds to even + (BitConverter.UInt64BitsToDouble(0x3800E00000000001), + UInt16BitsToBFloat16(0b0_00000000_1000100)), // subnormal + ULP rounds up + (BitConverter.UInt64BitsToDouble(0x3800E00000000000), + UInt16BitsToBFloat16(0b0_00000000_1000100)), // subnormal rounds to even + (BitConverter.UInt64BitsToDouble(0x3800DFFFFFFFFFFF), + UInt16BitsToBFloat16(0b0_00000000_1000011)), // subnormal - ULP rounds down + (BitConverter.UInt64BitsToDouble(0xB800DFFFFFFFFFFF), + UInt16BitsToBFloat16(0b1_00000000_1000011)), // neg subnormal + ULP rounds higher + (BitConverter.UInt64BitsToDouble(0xB800E00000000000), + UInt16BitsToBFloat16(0b1_00000000_1000100)), // neg subnormal rounds to even + (BitConverter.UInt64BitsToDouble(0xB800E00000000001), + UInt16BitsToBFloat16(0b1_00000000_1000100)), // neg subnormal - ULP rounds lower + (BitConverter.UInt64BitsToDouble(0x3788000000000000), UInt16BitsToBFloat16(0b0_00000_000000000)), // (BFloat16 minimum subnormal / 2) should underflow to zero + }; + + foreach ((double original, BFloat16 expected) in data) + { + yield return new object[] { original, expected }; + } + } + + [MemberData(nameof(ExplicitConversion_FromDouble_TestData))] + [Theory] + public static void ExplicitConversion_FromDouble(double d, BFloat16 expected) // Check the underlying bits for verifying NaNs + { + BFloat16 b16 = (BFloat16)d; + AssertExtensions.Equal(BFloat16ToUInt16Bits(expected), BFloat16ToUInt16Bits(b16)); + } } } From 4059b6691c7e8ef31e00c5729334ab26ae879309 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 9 Jun 2024 23:35:01 +0800 Subject: [PATCH 47/67] Parse tests --- .../System/Numerics/BFloat16Tests.cs | 292 ++++++++++++++++++ 1 file changed, 292 insertions(+) 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 df086a55f91f27..86665c0f9603d2 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 @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Globalization; using System.Runtime.CompilerServices; +using System.Text; using Xunit; namespace System.Numerics.Tests @@ -625,5 +627,295 @@ public static IEnumerable ExplicitConversion_FromDouble_TestData() BFloat16 b16 = (BFloat16)d; AssertExtensions.Equal(BFloat16ToUInt16Bits(expected), BFloat16ToUInt16Bits(b16)); } + + public static IEnumerable Parse_Valid_TestData() + { + NumberStyles defaultStyle = NumberStyles.Float | NumberStyles.AllowThousands; + + NumberFormatInfo emptyFormat = NumberFormatInfo.CurrentInfo; + + var dollarSignCommaSeparatorFormat = new NumberFormatInfo() + { + CurrencySymbol = "$", + CurrencyGroupSeparator = "," + }; + + var decimalSeparatorFormat = new NumberFormatInfo() + { + NumberDecimalSeparator = "." + }; + + NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; + + yield return new object[] { "-123", defaultStyle, null, -123.0f }; + yield return new object[] { "0", defaultStyle, null, 0.0f }; + yield return new object[] { "123", defaultStyle, null, 123.0f }; + yield return new object[] { " 123 ", defaultStyle, null, 123.0f }; + yield return new object[] { (567.89f).ToString(), defaultStyle, null, 567.89f }; + yield return new object[] { (-567.89f).ToString(), defaultStyle, null, -567.89f }; + yield return new object[] { "1E23", defaultStyle, null, 1E23f }; + + yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, 0.234f }; + yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 234.0f }; + yield return new object[] { new string('0', 13) + "338953138925153547590470800371487866880" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 3.3895314e38f }; + yield return new object[] { new string('0', 14) + "338953138925153547590470800371487866880" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 3.3895314e38f }; + + // 2^11 + 1. Not exactly representable + yield return new object[] { "2049.0", defaultStyle, invariantFormat, 2048.0f }; + yield return new object[] { "2049.000000000000001", defaultStyle, invariantFormat, 2050.0f }; + yield return new object[] { "2049.0000000000000001", defaultStyle, invariantFormat, 2050.0f }; + yield return new object[] { "2049.00000000000000001", defaultStyle, invariantFormat, 2050.0f }; + yield return new object[] { "5.000000000000000004", defaultStyle, invariantFormat, 5.0f }; + yield return new object[] { "5.0000000000000000004", defaultStyle, invariantFormat, 5.0f }; + yield return new object[] { "5.004", defaultStyle, invariantFormat, 5.004f }; + yield return new object[] { "5.004000000000000000", defaultStyle, invariantFormat, 5.004f }; + yield return new object[] { "5.0040000000000000000", defaultStyle, invariantFormat, 5.004f }; + yield return new object[] { "5.040", defaultStyle, invariantFormat, 5.04f }; + + yield return new object[] { "5004.000000000000000", defaultStyle, invariantFormat, 5004.0f }; + yield return new object[] { "50040.0", defaultStyle, invariantFormat, 50040.0f }; + yield return new object[] { "5004", defaultStyle, invariantFormat, 5004.0f }; + yield return new object[] { "050040", defaultStyle, invariantFormat, 50040.0f }; + yield return new object[] { "0.000000000000000000", defaultStyle, invariantFormat, 0.0f }; + yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005f }; + yield return new object[] { "0.0400", defaultStyle, invariantFormat, 0.04f }; + yield return new object[] { "1200e0", defaultStyle, invariantFormat, 1200.0f }; + yield return new object[] { "120100e-4", defaultStyle, invariantFormat, 12.01f }; + yield return new object[] { "12010.00e-4", defaultStyle, invariantFormat, 1.201f }; + yield return new object[] { "12000e-4", defaultStyle, invariantFormat, 1.2f }; + yield return new object[] { "1200", defaultStyle, invariantFormat, 1200.0f }; + + yield return new object[] { (123.1f).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1f }; + yield return new object[] { (1000.0f).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0f }; + + yield return new object[] { "123", NumberStyles.Any, emptyFormat, 123.0f }; + yield return new object[] { (123.567f).ToString(), NumberStyles.Any, emptyFormat, 123.567f }; + yield return new object[] { "123", NumberStyles.Float, emptyFormat, 123.0f }; + yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0f }; + yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0f }; + yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, 123.123f }; + yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, -123.0f }; + + yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, float.NaN }; + yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, float.PositiveInfinity }; + yield return new object[] { "-Infinity", NumberStyles.Any, invariantFormat, float.NegativeInfinity }; + } + + [Theory] + [MemberData(nameof(Parse_Valid_TestData))] + public static void Parse(string value, NumberStyles style, IFormatProvider provider, float expectedFloat) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + BFloat16 result; + BFloat16 expected = (BFloat16)expectedFloat; + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.True(BFloat16.TryParse(value, out result)); + Assert.True(expected.Equals(result)); + + Assert.Equal(expected, BFloat16.Parse(value)); + } + + Assert.True(expected.Equals(BFloat16.Parse(value, provider: provider))); + } + + // Use Parse(string, NumberStyles, IFormatProvider) + Assert.True(BFloat16.TryParse(value, style, provider, out result)); + Assert.True(expected.Equals(result) || (BFloat16.IsNaN(expected) && BFloat16.IsNaN(result))); + + Assert.True(expected.Equals(BFloat16.Parse(value, style, provider)) || (BFloat16.IsNaN(expected) && BFloat16.IsNaN(result))); + + if (isDefaultProvider) + { + // Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider) + Assert.True(BFloat16.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); + Assert.True(expected.Equals(result)); + + Assert.True(expected.Equals(BFloat16.Parse(value, style))); + Assert.True(expected.Equals(BFloat16.Parse(value, style, NumberFormatInfo.CurrentInfo))); + } + } + + public static IEnumerable Parse_Invalid_TestData() + { + NumberStyles defaultStyle = NumberStyles.Float; + + var dollarSignDecimalSeparatorFormat = new NumberFormatInfo(); + dollarSignDecimalSeparatorFormat.CurrencySymbol = "$"; + dollarSignDecimalSeparatorFormat.NumberDecimalSeparator = "."; + + yield return new object[] { null, defaultStyle, null, typeof(ArgumentNullException) }; + yield return new object[] { "", defaultStyle, null, typeof(FormatException) }; + yield return new object[] { " ", defaultStyle, null, typeof(FormatException) }; + yield return new object[] { "Garbage", defaultStyle, null, typeof(FormatException) }; + + yield return new object[] { "ab", defaultStyle, null, typeof(FormatException) }; // Hex value + yield return new object[] { "(123)", defaultStyle, null, typeof(FormatException) }; // Parentheses + yield return new object[] { (100.0f).ToString("C0"), defaultStyle, null, typeof(FormatException) }; // Currency + + yield return new object[] { (123.456f).ToString(), NumberStyles.Integer, null, typeof(FormatException) }; // Decimal + yield return new object[] { " " + (123.456f).ToString(), NumberStyles.None, null, typeof(FormatException) }; // Leading space + yield return new object[] { (123.456f).ToString() + " ", NumberStyles.None, null, typeof(FormatException) }; // Leading space + yield return new object[] { "1E23", NumberStyles.None, null, typeof(FormatException) }; // Exponent + + yield return new object[] { "ab", NumberStyles.None, null, typeof(FormatException) }; // Negative hex value + yield return new object[] { " 123 ", NumberStyles.None, null, typeof(FormatException) }; // Trailing and leading whitespace + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + BFloat16 result; + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None && (style & NumberStyles.AllowLeadingWhite) == (style & NumberStyles.AllowTrailingWhite)) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.False(BFloat16.TryParse(value, out result)); + Assert.Equal(default(BFloat16), result); + + Assert.Throws(exceptionType, () => BFloat16.Parse(value)); + } + + Assert.Throws(exceptionType, () => BFloat16.Parse(value, provider: provider)); + } + + // Use Parse(string, NumberStyles, IFormatProvider) + Assert.False(BFloat16.TryParse(value, style, provider, out result)); + Assert.Equal(default(BFloat16), result); + + Assert.Throws(exceptionType, () => BFloat16.Parse(value, style, provider)); + + if (isDefaultProvider) + { + // Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider) + Assert.False(BFloat16.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); + Assert.Equal(default(BFloat16), result); + + Assert.Throws(exceptionType, () => BFloat16.Parse(value, style)); + Assert.Throws(exceptionType, () => BFloat16.Parse(value, style, NumberFormatInfo.CurrentInfo)); + } + } + + public static IEnumerable Parse_ValidWithOffsetCount_TestData() + { + foreach (object[] inputs in Parse_Valid_TestData()) + { + yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] }; + } + + const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands; + + yield return new object[] { "-123", 1, 3, DefaultStyle, null, (float)123 }; + yield return new object[] { "-123", 0, 3, DefaultStyle, null, (float)-12 }; + yield return new object[] { "1E23", 0, 3, DefaultStyle, null, (float)1E2 }; + yield return new object[] { "123", 0, 2, NumberStyles.Float, new NumberFormatInfo(), (float)12 }; + yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$", CurrencyGroupSeparator = "," }, (float)10 }; + yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, (float)123 }; + yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, float.PositiveInfinity }; + } + + [Theory] + [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))] + public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, float expectedFloat) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + BFloat16 result; + BFloat16 expected = (BFloat16)expectedFloat; + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.True(BFloat16.TryParse(value.AsSpan(offset, count), out result)); + Assert.Equal(expected, result); + + Assert.Equal(expected, BFloat16.Parse(value.AsSpan(offset, count))); + } + + Assert.Equal(expected, BFloat16.Parse(value.AsSpan(offset, count), provider: provider)); + } + + Assert.True(expected.Equals(BFloat16.Parse(value.AsSpan(offset, count), style, provider)) || (BFloat16.IsNaN(expected) && BFloat16.IsNaN(BFloat16.Parse(value.AsSpan(offset, count), style, provider)))); + + Assert.True(BFloat16.TryParse(value.AsSpan(offset, count), style, provider, out result)); + Assert.True(expected.Equals(result) || (BFloat16.IsNaN(expected) && BFloat16.IsNaN(result))); + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + if (value != null) + { + Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider)); + + Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result)); + Assert.Equal(0, result); + } + } + + [Theory] + [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))] + public static void Parse_Utf8Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, float expectedFloat) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + + BFloat16 result; + BFloat16 expected = (BFloat16)expectedFloat; + + ReadOnlySpan valueUtf8 = Encoding.UTF8.GetBytes(value, offset, count); + + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.True(BFloat16.TryParse(valueUtf8, out result)); + Assert.Equal(expected, result); + + Assert.Equal(expected, BFloat16.Parse(valueUtf8)); + } + + Assert.Equal(expected, BFloat16.Parse(valueUtf8, provider: provider)); + } + + Assert.True(expected.Equals(BFloat16.Parse(valueUtf8, style, provider)) || (BFloat16.IsNaN(expected) && BFloat16.IsNaN(BFloat16.Parse(value.AsSpan(offset, count), style, provider)))); + + Assert.True(BFloat16.TryParse(valueUtf8, style, provider, out result)); + Assert.True(expected.Equals(result) || (BFloat16.IsNaN(expected) && BFloat16.IsNaN(result))); + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + if (value != null) + { + ReadOnlySpan valueUtf8 = Encoding.UTF8.GetBytes(value); + Exception e = Assert.Throws(exceptionType, () => BFloat16.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } + + Assert.False(float.TryParse(valueUtf8, style, provider, out float result)); + Assert.Equal(0, result); + } + } + + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => BFloat16.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); + } } } From 4b4d1a5f542aad37baac1db8698fde39b69f88bb Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 10 Jun 2024 00:05:30 +0800 Subject: [PATCH 48/67] Formatting tests --- .../System/Numerics/BFloat16Tests.cs | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) 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 86665c0f9603d2..dd836904d5c27a 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 @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.Runtime.CompilerServices; +using System.Tests; using System.Text; using Xunit; @@ -917,5 +918,134 @@ public static void Parse_Utf8Span_InvalidUtf8() Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } + + public static IEnumerable ToString_TestData() + { + yield return new object[] { -4580.0f, "G", null, "-4580" }; + yield return new object[] { 0.0f, "G", null, "0" }; + yield return new object[] { 4580.0f, "G", null, "4580" }; + + yield return new object[] { float.NaN, "G", null, "NaN" }; + + yield return new object[] { 2464.0f, "N", null, "2,464.00" }; + + // Changing the negative pattern doesn't do anything without also passing in a format string + var customNegativePattern = new NumberFormatInfo() { NumberNegativePattern = 0 }; + yield return new object[] { -6300.0f, "G", customNegativePattern, "-6300" }; + + var customNegativeSignDecimalGroupSeparator = new NumberFormatInfo() + { + NegativeSign = "#", + NumberDecimalSeparator = "~", + NumberGroupSeparator = "*" + }; + yield return new object[] { -2464.0f, "N", customNegativeSignDecimalGroupSeparator, "#2*464~00" }; + yield return new object[] { 2464.0f, "N", customNegativeSignDecimalGroupSeparator, "2*464~00" }; + + var customNegativeSignGroupSeparatorNegativePattern = new NumberFormatInfo() + { + NegativeSign = "xx", // Set to trash to make sure it doesn't show up + NumberGroupSeparator = "*", + NumberNegativePattern = 0 + }; + yield return new object[] { -2464.0f, "N", customNegativeSignGroupSeparatorNegativePattern, "(2*464.00)" }; + + NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; + yield return new object[] { float.NaN, "G", invariantFormat, "NaN" }; + yield return new object[] { float.PositiveInfinity, "G", invariantFormat, "Infinity" }; + yield return new object[] { float.NegativeInfinity, "G", invariantFormat, "-Infinity" }; + } + + public static IEnumerable ToString_TestData_NotNetFramework() + { + foreach (var testData in ToString_TestData()) + { + yield return testData; + } + + yield return new object[] { BFloat16.MinValue, "G", null, "-3.39E+38" }; + yield return new object[] { BFloat16.MaxValue, "G", null, "3.39E+38" }; + + yield return new object[] { BFloat16.Epsilon, "G", null, "1E-40" }; + + NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; + yield return new object[] { BFloat16.Epsilon, "G", invariantFormat, "1E-40" }; + + yield return new object[] { 32.5f, "C100", invariantFormat, "\u00A432.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32.5f, "P100", invariantFormat, "3,250.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; + yield return new object[] { 32.5f, "E100", invariantFormat, "3.2500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; + yield return new object[] { 32.5f, "F100", invariantFormat, "32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32.5f, "N100", invariantFormat, "32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + } + + [Fact] + public static void Test_ToString_NotNetFramework() + { + using (new ThreadCultureChange(CultureInfo.InvariantCulture)) + { + foreach (object[] testdata in ToString_TestData_NotNetFramework()) + { + ToStringTest(testdata[0] is float floatData ? (BFloat16)floatData : (BFloat16)testdata[0], (string)testdata[1], (IFormatProvider)testdata[2], (string)testdata[3]); + } + } + } + + private static void ToStringTest(BFloat16 f, string format, IFormatProvider provider, string expected) + { + bool isDefaultProvider = provider == null; + if (string.IsNullOrEmpty(format) || format.ToUpperInvariant() == "G") + { + if (isDefaultProvider) + { + Assert.Equal(expected, f.ToString()); + Assert.Equal(expected, f.ToString((IFormatProvider)null)); + } + Assert.Equal(expected, f.ToString(provider)); + } + if (isDefaultProvider) + { + Assert.Equal(expected.Replace('e', 'E'), f.ToString(format.ToUpperInvariant())); // If format is upper case, then exponents are printed in upper case + Assert.Equal(expected.Replace('E', 'e'), f.ToString(format.ToLowerInvariant())); // If format is lower case, then exponents are printed in lower case + Assert.Equal(expected.Replace('e', 'E'), f.ToString(format.ToUpperInvariant(), null)); + Assert.Equal(expected.Replace('E', 'e'), f.ToString(format.ToLowerInvariant(), null)); + } + Assert.Equal(expected.Replace('e', 'E'), f.ToString(format.ToUpperInvariant(), provider)); + Assert.Equal(expected.Replace('E', 'e'), f.ToString(format.ToLowerInvariant(), provider)); + } + + [Fact] + public static void ToString_InvalidFormat_ThrowsFormatException() + { + BFloat16 f = (BFloat16)123.0f; + Assert.Throws(() => f.ToString("Y")); // Invalid format + Assert.Throws(() => f.ToString("Y", null)); // Invalid format + long intMaxPlus1 = (long)int.MaxValue + 1; + string intMaxPlus1String = intMaxPlus1.ToString(); + Assert.Throws(() => f.ToString("E" + intMaxPlus1String)); + } + + [Fact] + public static void TryFormat() + { + using (new ThreadCultureChange(CultureInfo.InvariantCulture)) + { + foreach (object[] testdata in ToString_TestData()) + { + float localI = (float)testdata[0]; + string localFormat = (string)testdata[1]; + IFormatProvider localProvider = (IFormatProvider)testdata[2]; + string localExpected = (string)testdata[3]; + + try + { + NumberFormatTestHelper.TryFormatNumberTest(localI, localFormat, localProvider, localExpected, formatCasingMatchesOutput: false); + } + catch (Exception exc) + { + throw new Exception($"Failed on `{localI}`, `{localFormat}`, `{localProvider}`, `{localExpected}`. {exc}"); + } + } + } + } } } From 6ed52f51bd1313d4acdd607d433aa5b942e678a3 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 10 Jun 2024 00:23:56 +0800 Subject: [PATCH 49/67] RoundTripping tests --- .../System/Numerics/BFloat16Tests.cs | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) 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 dd836904d5c27a..d633b285e08110 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 @@ -1047,5 +1047,88 @@ public static void TryFormat() } } } + + public static IEnumerable ToStringRoundtrip_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.MinValue }; + yield return new object[] { -MathF.PI }; + yield return new object[] { -MathF.E }; + yield return new object[] { -0.845512408f }; + yield return new object[] { -0.0f }; + yield return new object[] { BFloat16.NaN }; + yield return new object[] { 0.0f }; + yield return new object[] { 0.845512408f }; + yield return new object[] { BFloat16.Epsilon }; + yield return new object[] { MathF.E }; + yield return new object[] { MathF.PI }; + yield return new object[] { BFloat16.MaxValue }; + yield return new object[] { BFloat16.PositiveInfinity }; + + yield return new object[] { (UInt16BitsToBFloat16(0b0_00000001_0000000)) }; // smallest normal + yield return new object[] { (UInt16BitsToBFloat16(0b0_00000000_1111111)) }; // largest subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b0_00000000_1000000)) }; // middle subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b0_00000000_0111111)) }; // just below middle subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b0_00000000_0000000)) }; // smallest subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b1_00000000_0000000)) }; // highest negative subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b1_00000000_0111111)) }; // just above negative middle subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b1_00000000_1000000)) }; // negative middle subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b1_00000000_1111111)) }; // lowest negative subnormal + yield return new object[] { (UInt16BitsToBFloat16(0b1_00000001_0000000)) }; // highest negative normal + } + + [Theory] + [MemberData(nameof(ToStringRoundtrip_TestData))] + public static void ToStringRoundtrip(object o_value) + { + float value = o_value is float floatValue ? floatValue : (float)(BFloat16)o_value; + BFloat16 result = BFloat16.Parse(value.ToString()); + AssertExtensions.Equal(BFloat16ToUInt16Bits((BFloat16)value), BFloat16ToUInt16Bits(result)); + } + + [Theory] + [MemberData(nameof(ToStringRoundtrip_TestData))] + public static void ToStringRoundtrip_R(object o_value) + { + float value = o_value is float floatValue ? floatValue : (float)(BFloat16)o_value; + BFloat16 result = BFloat16.Parse(value.ToString("R")); + AssertExtensions.Equal(BFloat16ToUInt16Bits((BFloat16)value), BFloat16ToUInt16Bits(result)); + } + + public static IEnumerable RoundTripFloat_CornerCases() + { + // Magnitude smaller than 2^-133 maps to 0 + yield return new object[] { (BFloat16)(4.6e-41f), 0 }; + yield return new object[] { (BFloat16)(-4.6e-41f), 0 }; + // Magnitude smaller than 2^(map to subnormals + yield return new object[] { (BFloat16)(0.567e-39f), 0.567e-39f }; + yield return new object[] { (BFloat16)(-0.567e-39f), -0.567e-39f }; + // Normal numbers + yield return new object[] { (BFloat16)(55.77f), 55.75f }; + yield return new object[] { (BFloat16)(-55.77f), -55.75f }; + // Magnitude smaller than 2^(map to infinity + yield return new object[] { (BFloat16)(float.BitDecrement(float.PositiveInfinity)), float.PositiveInfinity }; + yield return new object[] { (BFloat16)(float.BitIncrement(float.NegativeInfinity)), float.NegativeInfinity }; + // Infinity and NaN map to infinity and Nan + yield return new object[] { BFloat16.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { BFloat16.NaN, float.NaN }; + } + + [Theory] + [MemberData(nameof(RoundTripFloat_CornerCases))] + public static void ToSingle(BFloat16 BFloat16, float verify) + { + float f = (float)BFloat16; + Assert.Equal(f, verify, precision: 1); + } + + [Fact] + public static void EqualityMethodAndOperator() + { + Assert.True(BFloat16.NaN.Equals(BFloat16.NaN)); + Assert.False(BFloat16.NaN == BFloat16.NaN); + Assert.Equal(BFloat16.NaN, BFloat16.NaN); + } } } From 14b0d854392ceae0241a89c452508e3c68363e1a Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 10 Jun 2024 20:52:04 +0800 Subject: [PATCH 50/67] Port float->Half conversion algorithm to double->BFloat16 to handle ULP rounding. --- .../System.Private.CoreLib/src/System/Half.cs | 6 +-- .../src/System/Numerics/BFloat16.cs | 54 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 21e21031ba0c93..85258d052b0c32 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -738,8 +738,8 @@ public static explicit operator Half(float value) const uint SingleBiasedExponentMask = float.BiasedExponentMask; // Exponent displacement #2 const uint Exponent13 = 0x0680_0000u; - // Maximum value that is not Infinity in Half - const float MaxHalfValueBelowInfinity = 65520.0f; + // The value above Half.MaxValue + const float HalfAboveMaxValue = 65520.0f; // Mask for exponent bits in Half const uint ExponentMask = BiasedExponentMask; uint bitValue = BitConverter.SingleToUInt32Bits(value); @@ -750,7 +750,7 @@ public static explicit operator Half(float value) // Clear sign bit value = float.Abs(value); // Rectify values that are Infinity in Half. (float.Min now emits vminps instruction if one of two arguments is a constant) - value = float.Min(MaxHalfValueBelowInfinity, value); + value = float.Min(HalfAboveMaxValue, value); // Rectify lower exponent uint exponentOffset0 = BitConverter.SingleToUInt32Bits(float.Max(value, BitConverter.UInt32BitsToSingle(MinExp))); // Extract 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 58d20219d523f7..2b4b7045281214 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -455,7 +455,59 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(double value) => (BFloat16)(float)value; + public static explicit operator BFloat16(double value) + { + // See explaination of the algorithm at Half.operator Half(float) + + // Minimum exponent for rounding + const ulong MinExp = 0x3810_0000_0000_0000u; + // Exponent displacement #1 + const ulong Exponent942 = 0x3ae0_0000_0000_0000u; + // Exponent mask + const ulong SingleBiasedExponentMask = double.BiasedExponentMask; + // Exponent displacement #2 + const ulong Exponent45 = 0x02D0_0000_0000_0000u; + // The value above BFloat16.MaxValue + const double BFloat16AboveMaxValue = 3.39617752923046E+38; + // Mask for exponent bits in BFloat16 + const ulong ExponentMask = BiasedExponentMask; + ulong bitValue = BitConverter.DoubleToUInt64Bits(value); + // Extract sign bit + ulong sign = (bitValue & double.SignMask) >> 48; + // Detecting NaN (~0u if a is not NaN) + ulong realMask = (ulong)(Unsafe.BitCast(double.IsNaN(value)) - 1); + // Clear sign bit + value = double.Abs(value); + // Rectify values that are Infinity in BFloat16. (float.Min now emits vminps instruction if one of two arguments is a constant) + value = double.Min(BFloat16AboveMaxValue, value); + // Rectify lower exponent + ulong exponentOffset0 = BitConverter.DoubleToUInt64Bits(double.Max(value, BitConverter.UInt64BitsToDouble(MinExp))); + // Extract exponent + exponentOffset0 &= SingleBiasedExponentMask; + // Add exponent by 45 + exponentOffset0 += Exponent45; + // Round Single into BFloat16's precision (NaN also gets modified here, just setting the MSB of fraction) + value += BitConverter.UInt64BitsToDouble(exponentOffset0); + bitValue = BitConverter.DoubleToUInt64Bits(value); + // Only exponent bits will be modified if NaN + ulong maskedBFloat16ExponentForNaN = ~realMask & ExponentMask; + // Subtract exponent by 942 + bitValue -= Exponent942; + // Shift bitValue right by 45 bits to match the boundary of exponent part and fraction part. + ulong newExponent = bitValue >> 45; + // Clear the fraction parts if the value was NaN. + bitValue &= realMask; + // Merge the exponent part with fraction part, and add the exponent part and fraction part's overflow. + bitValue += newExponent; + // Clear exponents if value is NaN + bitValue &= ~maskedBFloat16ExponentForNaN; + // Merge sign bit with possible NaN exponent + ulong signAndMaskedExponent = maskedBFloat16ExponentForNaN | sign; + // Merge sign bit and possible NaN exponent + bitValue |= signAndMaskedExponent; + // The final result + return new BFloat16((ushort)bitValue); + } /// Explicitly converts a value to its nearest representable value. /// The value to convert. From ea1dd5f175f1301a569fe5736f116e4aea9b6ef8 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 10 Jun 2024 21:58:20 +0800 Subject: [PATCH 51/67] Port function tests from Half --- .../System.Runtime.Tests/System/HalfTests.cs | 18 +- .../System/Numerics/BFloat16Tests.cs | 1259 ++++++++++++++++- 2 files changed, 1264 insertions(+), 13 deletions(-) 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 cba358e484accb..e3733a53f2f9d4 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 @@ -1692,17 +1692,17 @@ public static IEnumerable Hypot_TestData() [Theory] [MemberData(nameof(Hypot_TestData))] - public static void Hypot(float x, float y, float expectedResult, float allowedVariance) + public static void Hypot(Half x, Half y, Half expectedResult, Half allowedVariance) { - AssertExtensions.Equal(expectedResult, float.Hypot(-x, -y), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(-x, +y), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(+x, -y), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(+x, +y), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(-x, -y), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(-x, +y), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(+x, -y), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(+x, +y), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(-y, -x), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(-y, +x), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(+y, -x), allowedVariance); - AssertExtensions.Equal(expectedResult, float.Hypot(+y, +x), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(-y, -x), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(-y, +x), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(+y, -x), allowedVariance); + AssertExtensions.Equal(expectedResult, Half.Hypot(+y, +x), allowedVariance); } public static IEnumerable RootN_TestData() 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 d633b285e08110..50f999e479c840 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 @@ -7,11 +7,14 @@ using System.Tests; using System.Text; using Xunit; +using Xunit.Sdk; namespace System.Numerics.Tests { public class BFloat16Tests { + private static BFloat16 CrossPlatformMachineEpsilon => (BFloat16)3.90625e-03f; + private static ushort BFloat16ToUInt16Bits(BFloat16 value) => Unsafe.BitCast(value); private static BFloat16 UInt16BitsToBFloat16(ushort value) => Unsafe.BitCast(value); @@ -542,7 +545,7 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() public static void ExplicitConversion_FromSingle(float f, BFloat16 expected) // Check the underlying bits for verifying NaNs { BFloat16 b16 = (BFloat16)f; - AssertExtensions.Equal(BFloat16ToUInt16Bits(expected), BFloat16ToUInt16Bits(b16)); + AssertEqual(expected, b16); } public static IEnumerable ExplicitConversion_FromDouble_TestData() @@ -626,7 +629,7 @@ public static IEnumerable ExplicitConversion_FromDouble_TestData() public static void ExplicitConversion_FromDouble(double d, BFloat16 expected) // Check the underlying bits for verifying NaNs { BFloat16 b16 = (BFloat16)d; - AssertExtensions.Equal(BFloat16ToUInt16Bits(expected), BFloat16ToUInt16Bits(b16)); + AssertEqual(expected, b16); } public static IEnumerable Parse_Valid_TestData() @@ -1083,7 +1086,7 @@ public static void ToStringRoundtrip(object o_value) { float value = o_value is float floatValue ? floatValue : (float)(BFloat16)o_value; BFloat16 result = BFloat16.Parse(value.ToString()); - AssertExtensions.Equal(BFloat16ToUInt16Bits((BFloat16)value), BFloat16ToUInt16Bits(result)); + AssertEqual((BFloat16)value, result); } [Theory] @@ -1092,7 +1095,7 @@ public static void ToStringRoundtrip_R(object o_value) { float value = o_value is float floatValue ? floatValue : (float)(BFloat16)o_value; BFloat16 result = BFloat16.Parse(value.ToString("R")); - AssertExtensions.Equal(BFloat16ToUInt16Bits((BFloat16)value), BFloat16ToUInt16Bits(result)); + AssertEqual((BFloat16)value, result); } public static IEnumerable RoundTripFloat_CornerCases() @@ -1130,5 +1133,1253 @@ public static void EqualityMethodAndOperator() Assert.False(BFloat16.NaN == BFloat16.NaN); Assert.Equal(BFloat16.NaN, BFloat16.NaN); } + + + public static IEnumerable MaxMagnitudeNumber_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NegativeInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.MinValue, BFloat16.MaxValue, BFloat16.MaxValue }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MinValue, BFloat16.MaxValue }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, (BFloat16)BFloat16.One, (BFloat16)BFloat16.One }; + yield return new object[] { (BFloat16)BFloat16.One, BFloat16.NaN, (BFloat16)BFloat16.One }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)0.0f, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)0.0f, (BFloat16)(-0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)2.0f, (BFloat16)(-3.0f), (BFloat16)(-3.0f) }; + yield return new object[] { (BFloat16)(-3.0f), (BFloat16)2.0f, (BFloat16)(-3.0f) }; + yield return new object[] { (BFloat16)3.0f, (BFloat16)(-2.0f), (BFloat16)3.0f }; + yield return new object[] { (BFloat16)(-2.0f), (BFloat16)3.0f, (BFloat16)3.0f }; + } + + [Theory] + [MemberData(nameof(MaxMagnitudeNumber_TestData))] + public static void MaxMagnitudeNumberTest(BFloat16 x, BFloat16 y, BFloat16 expectedResult) + { + AssertEqual(expectedResult, BFloat16.MaxMagnitudeNumber(x, y), (BFloat16)0.0f); + } + + public static IEnumerable MaxNumber_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NegativeInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.MinValue, BFloat16.MaxValue, BFloat16.MaxValue }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MinValue, BFloat16.MaxValue }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, (BFloat16)BFloat16.One, (BFloat16)BFloat16.One }; + yield return new object[] { (BFloat16)BFloat16.One, BFloat16.NaN, (BFloat16)BFloat16.One }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)0.0f, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)0.0f, (BFloat16)(-0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)2.0f, (BFloat16)(-3.0f), (BFloat16)2.0f }; + yield return new object[] { (BFloat16)(-3.0f), (BFloat16)2.0f, (BFloat16)2.0f }; + yield return new object[] { (BFloat16)3.0f, (BFloat16)(-2.0f), (BFloat16)3.0f }; + yield return new object[] { (BFloat16)(-2.0f), (BFloat16)3.0f, (BFloat16)3.0f }; + } + + [Theory] + [MemberData(nameof(MaxNumber_TestData))] + public static void MaxNumberTest(BFloat16 x, BFloat16 y, BFloat16 expectedResult) + { + AssertEqual(expectedResult, BFloat16.MaxNumber(x, y), (BFloat16)0.0f); + } + + public static IEnumerable MinMagnitudeNumber_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.PositiveInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.MinValue, BFloat16.MaxValue, BFloat16.MinValue }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MinValue, BFloat16.MinValue }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, (BFloat16)BFloat16.One, (BFloat16)BFloat16.One }; + yield return new object[] { (BFloat16)BFloat16.One, BFloat16.NaN, (BFloat16)BFloat16.One }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)0.0f, (BFloat16)(-0.0f) }; + yield return new object[] { (BFloat16)0.0f, (BFloat16)(-0.0f), (BFloat16)(-0.0f) }; + yield return new object[] { (BFloat16)2.0f, (BFloat16)(-3.0f), (BFloat16)2.0f }; + yield return new object[] { (BFloat16)(-3.0f), (BFloat16)2.0f, (BFloat16)2.0f }; + yield return new object[] { (BFloat16)3.0f, (BFloat16)(-2.0f), (BFloat16)(-2.0f) }; + yield return new object[] { (BFloat16)(-2.0f), (BFloat16)3.0f, (BFloat16)(-2.0f) }; + } + + [Theory] + [MemberData(nameof(MinMagnitudeNumber_TestData))] + public static void MinMagnitudeNumberTest(BFloat16 x, BFloat16 y, BFloat16 expectedResult) + { + AssertEqual(expectedResult, BFloat16.MinMagnitudeNumber(x, y), (BFloat16)0.0f); + } + + public static IEnumerable MinNumber_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.PositiveInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.MinValue, BFloat16.MaxValue, BFloat16.MinValue }; + yield return new object[] { BFloat16.MaxValue, BFloat16.MinValue, BFloat16.MinValue }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, (BFloat16)BFloat16.One, (BFloat16)BFloat16.One }; + yield return new object[] { (BFloat16)BFloat16.One, BFloat16.NaN, (BFloat16)BFloat16.One }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)0.0f, (BFloat16)(-0.0f) }; + yield return new object[] { (BFloat16)0.0f, (BFloat16)(-0.0f), (BFloat16)(-0.0f) }; + yield return new object[] { (BFloat16)2.0f, (BFloat16)(-3.0f), (BFloat16)(-3.0f) }; + yield return new object[] { (BFloat16)(-3.0f), (BFloat16)2.0f, (BFloat16)(-3.0f) }; + yield return new object[] { (BFloat16)3.0f, (BFloat16)(-2.0f), (BFloat16)(-2.0f) }; + yield return new object[] { (BFloat16)(-2.0f), (BFloat16)3.0f, (BFloat16)(-2.0f) }; + } + + [Theory] + [MemberData(nameof(MinNumber_TestData))] + public static void MinNumberTest(BFloat16 x, BFloat16 y, BFloat16 expectedResult) + { + AssertEqual(expectedResult, BFloat16.MinNumber(x, y), (BFloat16)0.0f); + } + + public static IEnumerable ExpM1_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(-0.956786082f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(-0.934011964f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(-0.9f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(-0.792120424f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(-0.763709912f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(-0.756883266f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(-0.676442736f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.632120559f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(-0.544061872f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(-0.506931309f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(-0.5f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(-0.470922192f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(-0.352278515f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(-0.272622651f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(0.374802227f), CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(0.543873444f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(0.890081165f), CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(1.02811498f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(1.19328005f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(1.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(2.09064302f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(3.11325038f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(3.23208611f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(3.81047738f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(9.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(14.1542622f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (e) + yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(22.1406926f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0.0 }; + } + + [Theory] + [MemberData(nameof(ExpM1_TestData))] + public static void ExpM1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.ExpM1(value), allowedVariance); + } + + public static IEnumerable Exp2_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(0.113314732f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(0.151955223f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(0.202699566f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(0.336622537f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(0.367879441f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(0.375214227f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(0.457429347f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(0.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(0.580191810f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(0.612547327f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(0.618503138f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(0.643218242f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(0.740055574f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(0.802008879f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(BFloat16.One), (BFloat16)0.0f }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(BFloat16.One), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(1.24686899f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(1.35124987f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(1.55468228f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(1.61680667f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(1.63252692f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(1.72356793f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(2.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(2.18612996f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(2.66514414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(2.97068642f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(4.93340967f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(6.58088599f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) + yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(8.82497783f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0.0f }; + } + + [Theory] + [MemberData(nameof(Exp2_TestData))] + public static void Exp2Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Exp2(value), allowedVariance); + } + + public static IEnumerable Exp2M1_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(-BFloat16.One), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(-0.886685268f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(-0.848044777f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(-0.797300434f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(-0.663377463f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(-0.632120559f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(-0.624785773f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(-0.542570653f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(-0.419808190f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(-0.387452673f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(-0.381496862f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(-0.356781758f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(-0.259944426f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(-0.197991121f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(0.246868989f), CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(0.351249873f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(0.554682275f), CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(0.616806672f), CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(0.632526919f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(0.723567934f), CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(1.18612996f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(1.66514414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(1.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(1.97068642f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(3.93340967f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(5.58088599f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) + yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(7.82497783f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; + } + + [Theory] + [MemberData(nameof(Exp2M1_TestData))] + public static void Exp2M1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Exp2M1(value), allowedVariance); + } + + public static IEnumerable Exp10_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)0.0f, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)0.000721784159f, CrossPlatformMachineEpsilon / (BFloat16)1000 }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)0.00191301410f, CrossPlatformMachineEpsilon / (BFloat16)100 }; // value: -(e) + yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)0.00498212830f, CrossPlatformMachineEpsilon / (BFloat16)100 }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)0.0268660410f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)0.0360831928f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)0.0385288847f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)0.0744082059f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)0.1f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)0.163908636f, CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)0.196287760f, CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)0.202699566f, CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)0.230876765f, CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)0.367879441f, CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)0.480496373f, CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)BFloat16.One, (BFloat16)0.0f }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)BFloat16.One, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)2.08118116f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)2.71828183f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)4.33131503f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)4.93340967f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)5.09456117f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)6.10095980f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; + yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)13.4393779f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)25.9545535f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)27.7137338f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)37.2217105f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)200.717432f, CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)522.735300f, CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (e) + yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)1385.45573f, CrossPlatformMachineEpsilon * (BFloat16)10000 }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; + } + + [Theory] + [MemberData(nameof(Exp10_TestData))] + public static void Exp10Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Exp10(value), allowedVariance); + } + + public static IEnumerable Exp10M1_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(-BFloat16.One), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(-0.999278216f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(-0.998086986f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(-0.995017872f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(-0.973133959f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(-0.963916807f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(-0.961471115f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(-0.925591794f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.9f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(-0.836091364f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(-0.803712240f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(-0.797300434f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(-0.769123235f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(-0.632120559f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(-0.519503627f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(1.08118116f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(1.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(3.33131503f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(3.93340967f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(4.09456117f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(5.10095980f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(9.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(12.4393779f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(24.9545535f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(26.7137338f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(36.2217105f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(199.717432f), CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(521.735300f), CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (e) + yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(1384.45573f), CrossPlatformMachineEpsilon * (BFloat16)10000 }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; + } + + [Theory] + [MemberData(nameof(Exp10M1_TestData))] + public static void Exp10M1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Exp10M1(value), allowedVariance); + } + + public static IEnumerable LogP1_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-3.14159265f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(e) + yield return new object[] { (BFloat16)(-1.41421356f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(sqrt(2)) + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-BFloat16.One), BFloat16.NegativeInfinity, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-0.956786082f), (BFloat16)(-3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi) + yield return new object[] { (BFloat16)(-0.934011964f), (BFloat16)(-2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) + yield return new object[] { (BFloat16)(-0.9f), (BFloat16)(-2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) + yield return new object[] { (BFloat16)(-0.792120424f), (BFloat16)(-1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) + yield return new object[] { (BFloat16)(-0.763709912f), (BFloat16)(-1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) + yield return new object[] { (BFloat16)(-0.756883266f), (BFloat16)(-1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) + yield return new object[] { (BFloat16)(-0.676442736f), (BFloat16)(-1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-0.632120559f), (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(-0.544061872f), (BFloat16)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { (BFloat16)(-0.506931309f), (BFloat16)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.5f), (BFloat16)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { (BFloat16)(-0.470922192f), (BFloat16)(-0.636619772f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), 0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), 0.0f }; + yield return new object[] { (BFloat16)(0.374802227f), (BFloat16)(0.318309886f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { (BFloat16)(0.543873444f), (BFloat16)(0.434294482f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { (BFloat16)(0.890081165f), (BFloat16)(0.636619772f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(0.693147181f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { (BFloat16)(1.02811498f), (BFloat16)(0.707106781f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(1.19328005f), (BFloat16)(0.785398163f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { (BFloat16)(1.71828183f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(2.09064302f), (BFloat16)(1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(3.11325038f), (BFloat16)(1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) + yield return new object[] { (BFloat16)(3.23208611f), (BFloat16)(1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) + yield return new object[] { (BFloat16)(3.81047738f), (BFloat16)(1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) + yield return new object[] { (BFloat16)(9.0f), (BFloat16)(2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) + yield return new object[] { (BFloat16)(14.1542622f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) + yield return new object[] { (BFloat16)(22.1406926f), (BFloat16)(3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; + } + + [Theory] + [MemberData(nameof(LogP1_TestData))] + public static void LogP1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.LogP1(value), allowedVariance); + } + + public static IEnumerable Log2P1_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-BFloat16.One), BFloat16.NegativeInfinity, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-0.886685268f), (BFloat16)(-3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi) + yield return new object[] { (BFloat16)(-0.848044777f), (BFloat16)(-2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) + yield return new object[] { (BFloat16)(-0.797300434f), (BFloat16)(-2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) + yield return new object[] { (BFloat16)(-0.663377463f), (BFloat16)(-1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) + yield return new object[] { (BFloat16)(-0.632120559f), (BFloat16)(-1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) + yield return new object[] { (BFloat16)(-0.624785773f), (BFloat16)(-1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) + yield return new object[] { (BFloat16)(-0.542570653f), (BFloat16)(-1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-0.5f), (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(-0.419808190f), (BFloat16)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { (BFloat16)(-0.387452673f), (BFloat16)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.381496862f), (BFloat16)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { (BFloat16)(-0.356781758f), (BFloat16)(-0.636619772f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { (BFloat16)(-0.259944426f), (BFloat16)(-0.434294482f), CrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { (BFloat16)(-0.197991121f), (BFloat16)(-0.318309886f), CrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.246868989f), (BFloat16)(0.318309886f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { (BFloat16)(0.351249873f), (BFloat16)(0.434294482f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { (BFloat16)(0.554682275f), (BFloat16)(0.636619772f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { (BFloat16)(0.616806672f), (BFloat16)(0.693147181f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { (BFloat16)(0.632526919f), (BFloat16)(0.707106781f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.723567934f), (BFloat16)(0.785398163f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(1.18612996f), (BFloat16)(1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.66514414f), (BFloat16)(1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) + yield return new object[] { (BFloat16)(1.71828183f), (BFloat16)(1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) + yield return new object[] { (BFloat16)(1.97068642f), (BFloat16)(1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) + yield return new object[] { (BFloat16)(3.93340967f), (BFloat16)(2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) + yield return new object[] { (BFloat16)(5.58088599f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) + yield return new object[] { (BFloat16)(7.82497783f), (BFloat16)(3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; + } + + [Theory] + [MemberData(nameof(Log2P1_TestData))] + public static void Log2P1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Log2P1(value), allowedVariance); + } + + public static IEnumerable Log10P1_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-3.14159265f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.71828183f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(e) + yield return new object[] { (BFloat16)(-1.41421356f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(sqrt(2)) + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-BFloat16.One), BFloat16.NegativeInfinity, (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-0.998086986f), (BFloat16)(-2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) + yield return new object[] { (BFloat16)(-0.995017872f), (BFloat16)(-2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) + yield return new object[] { (BFloat16)(-0.973133959f), (BFloat16)(-1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) + yield return new object[] { (BFloat16)(-0.963916807f), (BFloat16)(-1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) + yield return new object[] { (BFloat16)(-0.961471115f), (BFloat16)(-1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) + yield return new object[] { (BFloat16)(-0.925591794f), (BFloat16)(-1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-0.9f), (BFloat16)(-1.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(-0.836091364f), (BFloat16)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { (BFloat16)(-0.803712240f), (BFloat16)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.797300434f), (BFloat16)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { (BFloat16)(-0.769123235f), (BFloat16)(-0.636619772f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { (BFloat16)(-0.632120559f), (BFloat16)(-0.434294482f), CrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { (BFloat16)(-0.519503627f), (BFloat16)(-0.318309886f), CrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(1.08118116f), (BFloat16)(0.318309886f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { (BFloat16)(1.71828183f), (BFloat16)(0.434294482f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) value: (e) + yield return new object[] { (BFloat16)(3.33131503f), (BFloat16)(0.636619772f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { (BFloat16)(3.93340967f), (BFloat16)(0.693147181f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { (BFloat16)(4.09456117f), (BFloat16)(0.707106781f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(5.10095980f), (BFloat16)(0.785398163f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { (BFloat16)(9.0f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(12.4393779f), (BFloat16)(1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(24.9545535f), (BFloat16)(1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) + yield return new object[] { (BFloat16)(26.7137338f), (BFloat16)(1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) + yield return new object[] { (BFloat16)(36.2217105f), (BFloat16)(1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) + yield return new object[] { (BFloat16)(199.717432f), (BFloat16)(2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) + yield return new object[] { (BFloat16)(521.735300f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) + yield return new object[] { (BFloat16)(1384.45573f), (BFloat16)(3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; + } + + [Theory] + [MemberData(nameof(Log10P1_TestData))] + public static void Log10P1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Log10P1(value), allowedVariance); + } + + public static IEnumerable Hypot_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, BFloat16.Zero, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, BFloat16.One, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, BFloat16.E, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, (BFloat16)10.0f, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.One, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, (BFloat16)1.57079633f, (BFloat16)1.57079633f, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, (BFloat16)2.0f, (BFloat16)2.0f, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.E, BFloat16.E, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, (BFloat16)3.0f, (BFloat16)3.0f, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, (BFloat16)10.0f, (BFloat16)10.0f, BFloat16.Zero }; + yield return new object[] { BFloat16.One, BFloat16.One, (BFloat16)1.41421356f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, (BFloat16)0.318309886f, (BFloat16)2.73685536f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (1 / pi) + yield return new object[] { BFloat16.E, (BFloat16)0.434294482f, (BFloat16)2.75275640f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (log10(e)) + yield return new object[] { BFloat16.E, (BFloat16)0.636619772f, (BFloat16)2.79183467f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (2 / pi) + yield return new object[] { BFloat16.E, (BFloat16)0.693147181f, (BFloat16)2.80526454f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (ln(2)) + yield return new object[] { BFloat16.E, (BFloat16)0.707106781f, (BFloat16)2.80874636f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (1 / sqrt(2)) + yield return new object[] { BFloat16.E, (BFloat16)0.785398163f, (BFloat16)2.82947104f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi / 4) + yield return new object[] { BFloat16.E, BFloat16.One, (BFloat16)2.89638673f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) + yield return new object[] { BFloat16.E, (BFloat16)1.12837917f, (BFloat16)2.94317781f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (2 / sqrt(pi)) + yield return new object[] { BFloat16.E, (BFloat16)1.41421356f, (BFloat16)3.06415667f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (sqrt(2)) + yield return new object[] { BFloat16.E, (BFloat16)1.44269504f, (BFloat16)3.07740558f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (log2(e)) + yield return new object[] { BFloat16.E, (BFloat16)1.57079633f, (BFloat16)3.13949951f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi / 2) + yield return new object[] { BFloat16.E, (BFloat16)2.30258509f, (BFloat16)3.56243656f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (ln(10)) + yield return new object[] { BFloat16.E, BFloat16.E, (BFloat16)3.84423103f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (e) + yield return new object[] { BFloat16.E, (BFloat16)3.14159265f, (BFloat16)4.15435440f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.318309886f, (BFloat16)10.0050648f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (1 / pi) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.434294482f, (BFloat16)10.0094261f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (log10(e)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.636619772f, (BFloat16)10.0202437f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (2 / pi) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.693147181f, (BFloat16)10.0239939f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (ln(2)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.707106781f, (BFloat16)10.0249688f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (1 / sqrt(2)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.785398163f, (BFloat16)10.0307951f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi / 4) + yield return new object[] { (BFloat16)10.0f, BFloat16.One, (BFloat16)10.0498756f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.12837917f, (BFloat16)10.0634606f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.41421356f, (BFloat16)10.0995049f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (sqrt(2)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.44269504f, (BFloat16)10.1035325f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (log2(e)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.57079633f, (BFloat16)10.1226183f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi / 2) + yield return new object[] { (BFloat16)10.0f, (BFloat16)2.30258509f, (BFloat16)10.2616713f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (ln(10)) + yield return new object[] { (BFloat16)10.0f, BFloat16.E, (BFloat16)10.3628691f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (e) + yield return new object[] { (BFloat16)10.0f, (BFloat16)3.14159265f, (BFloat16)10.4818703f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.Zero, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.One, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.E, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 10.0f, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(Hypot_TestData))] + public static void Hypot(BFloat16 x, BFloat16 y, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.Hypot(-x, -y), allowedVariance); + AssertEqual(expectedResult, BFloat16.Hypot(-x, +y), allowedVariance); + AssertEqual(expectedResult, BFloat16.Hypot(+x, -y), allowedVariance); + AssertEqual(expectedResult, BFloat16.Hypot(+x, +y), allowedVariance); + + AssertEqual(expectedResult, BFloat16.Hypot(-y, -x), allowedVariance); + AssertEqual(expectedResult, BFloat16.Hypot(-y, +x), allowedVariance); + AssertEqual(expectedResult, BFloat16.Hypot(+y, -x), allowedVariance); + AssertEqual(expectedResult, BFloat16.Hypot(+y, +x), allowedVariance); + } + + public static IEnumerable RootN_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, -5, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, -4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, -3, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, -2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, -1, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, 1, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, 2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, 3, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, 4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NegativeInfinity, 5, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { -BFloat16.E, -5, -(BFloat16)0.81873075f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { -BFloat16.E, -4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.E, -3, -(BFloat16)0.71653131f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { -BFloat16.E, -2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.E, -1, -(BFloat16)0.36787944f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { -BFloat16.E, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.E, 1, -BFloat16.E, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { -BFloat16.E, 2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.E, 3, -(BFloat16)1.39561243f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { -BFloat16.E, 4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.E, 5, -(BFloat16)1.22140276f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { -BFloat16.One, -5, -BFloat16.One, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, -4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, -3, -BFloat16.One, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, -2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, -1, -BFloat16.One, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, 1, -BFloat16.One, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, 2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, 3, -BFloat16.One, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, 4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.One, 5, -BFloat16.One, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, -5, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, -4, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, -3, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, -2, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, -1, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, 1, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, 2, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, 3, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, 4, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { -BFloat16.Zero, 5, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, -5, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, -4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, -3, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, -2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, -1, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, 1, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, 2, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, 3, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, 4, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.NaN, 5, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, -5, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, -4, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, -3, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, -2, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, -1, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, 1, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, 2, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, 3, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, 4, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, 5, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.One, -5, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, -4, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, -3, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, -2, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, -1, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.One, 1, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, 2, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, 3, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, 4, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.One, 5, BFloat16.One, BFloat16.Zero }; + yield return new object[] { BFloat16.E, -5, (BFloat16)0.81873075f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -4, (BFloat16)0.77880078f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -3, (BFloat16)0.71653131f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -2, (BFloat16)0.60653066f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -1, (BFloat16)0.36787944f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.E, 1, BFloat16.E, BFloat16.Zero }; + yield return new object[] { BFloat16.E, 2, (BFloat16)1.64872127f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 3, (BFloat16)1.39561243f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 4, (BFloat16)1.28402542f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 5, (BFloat16)1.22140276f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.PositiveInfinity, -5, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, -4, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, -3, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, -2, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, -1, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 0, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 1, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 2, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 3, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 4, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, 5, BFloat16.PositiveInfinity, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(RootN_TestData))] + public static void RootN(BFloat16 x, int n, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.RootN(x, n), allowedVariance); + } + + public static IEnumerable AcosPi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.One, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.540302306f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.204957194f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { BFloat16.Zero, (BFloat16)0.5f, BFloat16.Zero }; + yield return new object[] { -(BFloat16)0.416146837f, (BFloat16)0.636619772f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.570233249f, (BFloat16)0.693147181f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.605699867f, (BFloat16)0.707106781f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.781211892f, (BFloat16)0.785398163f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.0f, BFloat16.One, BFloat16.Zero }; + yield return new object[] { -(BFloat16)0.919764995f, (BFloat16)0.871620833f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.266255342f, (BFloat16)0.585786438f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.179057946f, (BFloat16)0.557304959f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.220584041f, (BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.581195664f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.633255651f, (BFloat16)0.718281828f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.902685362f, (BFloat16)0.858407346f, CrossPlatformMachineEpsilon }; + } + + [Theory] + [MemberData(nameof(AcosPi_TestData))] + public static void AcosPiTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(expectedResult, BFloat16.AcosPi(value), allowedVariance); + } + + public static IEnumerable AsinPi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.841470985f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.978770938f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { BFloat16.One, (BFloat16)0.5f, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.909297427f, (BFloat16)0.363380228f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.821482831f, (BFloat16)0.306852819f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.795693202f, (BFloat16)0.292893219f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.624265953f, (BFloat16)0.214601837f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.392469559f, -(BFloat16)0.128379167f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.963902533f, -(BFloat16)0.414213562f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.983838529f, -(BFloat16)0.442695041f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.975367972f, -(BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.813763848f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.773942685f, (BFloat16)0.281718172f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.430301217f, -(BFloat16)0.141592654f, CrossPlatformMachineEpsilon }; + } + + [Theory] + [MemberData(nameof(AsinPi_TestData))] + public static void AsinPiTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.AsinPi(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.AsinPi(+value), allowedVariance); + } + + public static IEnumerable Atan2Pi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, -BFloat16.One, BFloat16.One, BFloat16.Zero }; // y: sinpi(0) x: cospi(1) + yield return new object[] { BFloat16.Zero, -BFloat16.Zero, BFloat16.One, BFloat16.Zero }; // y: sinpi(0) x: -cospi(0.5) + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; // y: sinpi(0) x: cospi(0.5) + yield return new object[] { BFloat16.Zero, BFloat16.One, BFloat16.Zero, BFloat16.Zero }; // y: sinpi(0) x: cospi(0) + yield return new object[] { (BFloat16)0.841470985f, (BFloat16)0.540302306f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; // y: sinpi(1 / pi) x: cospi(1 / pi) + yield return new object[] { (BFloat16)0.978770938f, (BFloat16)0.204957194f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; // y: sinpi(log10(e)) x: cospi(log10(e)) + yield return new object[] { BFloat16.One, -BFloat16.Zero, (BFloat16)0.5f, BFloat16.Zero }; // y: sinpi(0.5) x: -cospi(0.5) + yield return new object[] { BFloat16.One, BFloat16.Zero, (BFloat16)0.5f, BFloat16.Zero }; // y: sinpi(0.5) x: cospi(0.5) + yield return new object[] { (BFloat16)0.909297427f, -(BFloat16)0.416146837f, (BFloat16)0.636619772f, CrossPlatformMachineEpsilon }; // y: sinpi(2 / pi) x: cospi(2 / pi) + yield return new object[] { (BFloat16)0.821482831f, -(BFloat16)0.570233249f, (BFloat16)0.693147181f, CrossPlatformMachineEpsilon }; // y: sinpi(ln(2)) x: cospi(ln(2)) + yield return new object[] { (BFloat16)0.795693202f, -(BFloat16)0.605699867f, (BFloat16)0.707106781f, CrossPlatformMachineEpsilon }; // y: sinpi(1 / sqrt(2)) x: cospi(1 / sqrt(2)) + yield return new object[] { (BFloat16)0.624265953f, -(BFloat16)0.781211892f, (BFloat16)0.785398163f, CrossPlatformMachineEpsilon }; // y: sinpi(pi / 4) x: cospi(pi / 4) + yield return new object[] { -(BFloat16)0.392469559f, -(BFloat16)0.919764995f, -(BFloat16)0.871620833f, CrossPlatformMachineEpsilon }; // y: sinpi(2 / sqrt(pi)) x: cospi(2 / sqrt(pi)) + yield return new object[] { -(BFloat16)0.963902533f, -(BFloat16)0.266255342f, -(BFloat16)0.585786438f, CrossPlatformMachineEpsilon }; // y: sinpi(sqrt(2)) x: cospi(sqrt(2)) + yield return new object[] { -(BFloat16)0.983838529f, -(BFloat16)0.179057946f, -(BFloat16)0.557304959f, CrossPlatformMachineEpsilon }; // y: sinpi(log2(e)) x: cospi(log2(e)) + yield return new object[] { -(BFloat16)0.975367972f, (BFloat16)0.220584041f, -(BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; // y: sinpi(pi / 2) x: cospi(pi / 2) + yield return new object[] { (BFloat16)0.813763848f, (BFloat16)0.581195664f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; // y: sinpi(ln(10)) x: cospi(ln(10)) + yield return new object[] { (BFloat16)0.773942685f, -(BFloat16)0.633255651f, (BFloat16)0.718281828f, CrossPlatformMachineEpsilon }; // y: sinpi(e) x: cospi(e) + yield return new object[] { -(BFloat16)0.430301217f, -(BFloat16)0.902685362f, -(BFloat16)0.858407346f, CrossPlatformMachineEpsilon }; // y: sinpi(pi) x: cospi(pi) + yield return new object[] { BFloat16.One, BFloat16.NegativeInfinity, BFloat16.One, BFloat16.Zero }; // y: sinpi(0.5) + yield return new object[] { BFloat16.One, BFloat16.PositiveInfinity, BFloat16.Zero, BFloat16.Zero }; // y: sinpi(0.5) + yield return new object[] { BFloat16.PositiveInfinity, -BFloat16.One, (BFloat16)0.5f, BFloat16.Zero }; // x: cospi(1) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.One, (BFloat16)0.5f, BFloat16.Zero }; // x: cospi(0) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NegativeInfinity, (BFloat16)0.75f, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.25f, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(Atan2Pi_TestData))] + public static void Atan2PiTest(BFloat16 y, BFloat16 x, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.Atan2Pi(-y, +x), allowedVariance); + AssertEqual(+expectedResult, BFloat16.Atan2Pi(+y, +x), allowedVariance); + } + + public static IEnumerable AtanPi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.55740773f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)4.77548954f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { BFloat16.PositiveInfinity, (BFloat16)0.5f, BFloat16.Zero }; + yield return new object[] { -(BFloat16)2.18503986f, -(BFloat16)0.363380228f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.44060844f, -(BFloat16)0.306852819f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.31367571f, -(BFloat16)0.292893219f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.79909940f, -(BFloat16)0.214601837f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.42670634f, (BFloat16)0.128379167f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)3.62021857f, (BFloat16)0.414213562f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)5.49452594f, (BFloat16)0.442695041f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)4.42175222f, -(BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)1.40015471f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.22216467f, -(BFloat16)0.281718172f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.476690146f, (BFloat16)0.141592654f, CrossPlatformMachineEpsilon }; + } + + [Theory] + [MemberData(nameof(AtanPi_TestData))] + public static void AtanPiTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.AtanPi(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.AtanPi(+value), allowedVariance); + } + + public static IEnumerable CosPi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.One, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.318309886f, (BFloat16)0.540302306f, CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)0.434294482f, (BFloat16)0.204957194f, CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)0.5f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.636619772f, -(BFloat16)0.416146837f, CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)0.693147181f, -(BFloat16)0.570233249f, CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)0.707106781f, -(BFloat16)0.605699867f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)0.785398163f, -(BFloat16)0.781211892f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { BFloat16.One, -(BFloat16)1.0f, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.12837917f, -(BFloat16)0.919764995f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)1.41421356f, -(BFloat16)0.266255342f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)1.44269504f, -(BFloat16)0.179057946f, CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)1.5f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.57079633f, (BFloat16)0.220584041f, CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)2.0f, (BFloat16)1.0, BFloat16.Zero }; + yield return new object[] { (BFloat16)2.30258509f, (BFloat16)0.581195664f, CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)2.5f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)2.71828183f, -(BFloat16)0.633255651f, CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)3.0f, -(BFloat16)1.0, BFloat16.Zero }; + yield return new object[] { (BFloat16)3.14159265f, -(BFloat16)0.902685362f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)3.5f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(CosPi_TestData))] + public static void CosPiTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(+expectedResult, BFloat16.CosPi(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.CosPi(+value), allowedVariance); + } + + public static IEnumerable SinPi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.318309886f, (BFloat16)0.841470985f, CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)0.434294482f, (BFloat16)0.978770938f, CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)0.5f, BFloat16.One, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.636619772f, (BFloat16)0.909297427f, CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)0.693147181f, (BFloat16)0.821482831f, CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)0.707106781f, (BFloat16)0.795693202f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)0.785398163f, (BFloat16)0.624265953f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { BFloat16.One, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.12837917f, -(BFloat16)0.392469559f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)1.41421356f, -(BFloat16)0.963902533f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)1.44269504f, -(BFloat16)0.983838529f, CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)1.5f, -(BFloat16)1.0f, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.57079633f, -(BFloat16)0.975367972f, CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)2.0f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)2.30258509f, (BFloat16)0.813763848f, CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)2.5f, BFloat16.One, BFloat16.Zero }; + yield return new object[] { (BFloat16)2.71828183f, (BFloat16)0.773942685f, CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)3.0f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)3.14159265f, -(BFloat16)0.430301217f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)3.5f, -(BFloat16)1.0f, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(SinPi_TestData))] + public static void SinPiTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.SinPi(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.SinPi(+value), allowedVariance); + } + + public static IEnumerable TanPi_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.318309886f, (BFloat16)1.55740772f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)0.434294482f, (BFloat16)4.77548954f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)0.5f, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { (BFloat16)0.636619772f, -(BFloat16)2.18503986f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)0.693147181f, -(BFloat16)1.44060844f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)0.707106781f, -(BFloat16)1.31367571f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)0.785398163f, -(BFloat16)0.799099398f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { BFloat16.One, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.12837917f, (BFloat16)0.426706344f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)1.41421356f, (BFloat16)3.62021857f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)1.44269504f, (BFloat16)5.49452594f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)1.5f, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.57079633f, -(BFloat16)4.42175222f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)2.0f, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)2.30258509f, (BFloat16)1.40015471f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)2.5f, BFloat16.PositiveInfinity, BFloat16.Zero }; + yield return new object[] { (BFloat16)2.71828183f, -(BFloat16)1.22216467f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) + yield return new object[] { (BFloat16)3.0f, -BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)3.14159265f, (BFloat16)0.476690146f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)3.5f, BFloat16.NegativeInfinity, BFloat16.Zero }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(TanPi_TestData))] + public static void TanPiTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.TanPi(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.TanPi(+value), allowedVariance); + } + + public static IEnumerable BitDecrement_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NegativeInfinity }; + yield return new object[] { UInt16BitsToBFloat16(0xC049), UInt16BitsToBFloat16(0xC04A) }; // value: -(pi) + yield return new object[] { UInt16BitsToBFloat16(0xC02E), UInt16BitsToBFloat16(0xC02F) }; // value: -(e) + yield return new object[] { UInt16BitsToBFloat16(0xC013), UInt16BitsToBFloat16(0xC014) }; // value: -(ln(10)) + yield return new object[] { UInt16BitsToBFloat16(0xBFC9), UInt16BitsToBFloat16(0xBFCA) }; // value: -(pi / 2) + yield return new object[] { UInt16BitsToBFloat16(0xBFB9), UInt16BitsToBFloat16(0xBFBA) }; // value: -(log2(e)) + yield return new object[] { UInt16BitsToBFloat16(0xBFB5), UInt16BitsToBFloat16(0xBFB6) }; // value: -(sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0xBF90), UInt16BitsToBFloat16(0xBF91) }; // value: -(2 / sqrt(pi)) + yield return new object[] { UInt16BitsToBFloat16(0xBF80), UInt16BitsToBFloat16(0xBF81) }; + yield return new object[] { UInt16BitsToBFloat16(0xBF49), UInt16BitsToBFloat16(0xBF4A) }; // value: -(pi / 4) + yield return new object[] { UInt16BitsToBFloat16(0xBF35), UInt16BitsToBFloat16(0xBF36) }; // value: -(1 / sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0xBF31), UInt16BitsToBFloat16(0xBF32) }; // value: -(ln(2)) + yield return new object[] { UInt16BitsToBFloat16(0xBF23), UInt16BitsToBFloat16(0xBF24) }; // value: -(2 / pi) + yield return new object[] { UInt16BitsToBFloat16(0xBEDE), UInt16BitsToBFloat16(0xBEDF) }; // value: -(log10(e)) + yield return new object[] { UInt16BitsToBFloat16(0xBEA3), UInt16BitsToBFloat16(0xBEA4) }; // value: -(1 / pi) + yield return new object[] { UInt16BitsToBFloat16(0x8000), -BFloat16.Epsilon }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN }; + yield return new object[] { UInt16BitsToBFloat16(0x0000), -BFloat16.Epsilon }; + yield return new object[] { UInt16BitsToBFloat16(0x3EA3), UInt16BitsToBFloat16(0x3EA2) }; // value: (1 / pi) + yield return new object[] { UInt16BitsToBFloat16(0x3EDE), UInt16BitsToBFloat16(0x3EDD) }; // value: (log10(e)) + yield return new object[] { UInt16BitsToBFloat16(0x3F23), UInt16BitsToBFloat16(0x3F22) }; // value: (2 / pi) + yield return new object[] { UInt16BitsToBFloat16(0x3F31), UInt16BitsToBFloat16(0x3F30) }; // value: (ln(2)) + yield return new object[] { UInt16BitsToBFloat16(0x3F35), UInt16BitsToBFloat16(0x3F34) }; // value: (1 / sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0x3F49), UInt16BitsToBFloat16(0x3F48) }; // value: (pi / 4) + yield return new object[] { UInt16BitsToBFloat16(0x3F80), UInt16BitsToBFloat16(0x3F7F) }; + yield return new object[] { UInt16BitsToBFloat16(0x3F90), UInt16BitsToBFloat16(0x3F8F) }; // value: (2 / sqrt(pi)) + yield return new object[] { UInt16BitsToBFloat16(0x3FB5), UInt16BitsToBFloat16(0x3FB4) }; // value: (sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0x3FB9), UInt16BitsToBFloat16(0x3FB8) }; // value: (log2(e)) + yield return new object[] { UInt16BitsToBFloat16(0x3FC9), UInt16BitsToBFloat16(0x3FC8) }; // value: (pi / 2) + yield return new object[] { UInt16BitsToBFloat16(0x4013), UInt16BitsToBFloat16(0x4012) }; // value: (ln(10)) + yield return new object[] { UInt16BitsToBFloat16(0x402E), UInt16BitsToBFloat16(0x402D) }; // value: (e) + yield return new object[] { UInt16BitsToBFloat16(0x4049), UInt16BitsToBFloat16(0x4048) }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.MaxValue }; + } + + [Theory] + [MemberData(nameof(BitDecrement_TestData))] + public static void BitDecrement(BFloat16 value, BFloat16 expectedResult) + { + AssertEqual(expectedResult, BFloat16.BitDecrement(value), BFloat16.Zero); + } + + public static IEnumerable BitIncrement_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.MinValue }; + yield return new object[] { UInt16BitsToBFloat16(0xC049), UInt16BitsToBFloat16(0xC048) }; // value: -(pi) + yield return new object[] { UInt16BitsToBFloat16(0xC02E), UInt16BitsToBFloat16(0xC02D) }; // value: -(e) + yield return new object[] { UInt16BitsToBFloat16(0xC013), UInt16BitsToBFloat16(0xC012) }; // value: -(ln(10)) + yield return new object[] { UInt16BitsToBFloat16(0xBFC9), UInt16BitsToBFloat16(0xBFC8) }; // value: -(pi / 2) + yield return new object[] { UInt16BitsToBFloat16(0xBFB9), UInt16BitsToBFloat16(0xBFB8) }; // value: -(log2(e)) + yield return new object[] { UInt16BitsToBFloat16(0xBFB5), UInt16BitsToBFloat16(0xBFB4) }; // value: -(sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0xBF90), UInt16BitsToBFloat16(0xBF8F) }; // value: -(2 / sqrt(pi)) + yield return new object[] { UInt16BitsToBFloat16(0xBF80), UInt16BitsToBFloat16(0xBF7F) }; + yield return new object[] { UInt16BitsToBFloat16(0xBF49), UInt16BitsToBFloat16(0xBF48) }; // value: -(pi / 4) + yield return new object[] { UInt16BitsToBFloat16(0xBF35), UInt16BitsToBFloat16(0xBF34) }; // value: -(1 / sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0xBF31), UInt16BitsToBFloat16(0xBF30) }; // value: -(ln(2)) + yield return new object[] { UInt16BitsToBFloat16(0xBF23), UInt16BitsToBFloat16(0xBF22) }; // value: -(2 / pi) + yield return new object[] { UInt16BitsToBFloat16(0xBEDE), UInt16BitsToBFloat16(0xBEDD) }; // value: -(log10(e)) + yield return new object[] { UInt16BitsToBFloat16(0xBEA3), UInt16BitsToBFloat16(0xBEA2) }; // value: -(1 / pi) + yield return new object[] { UInt16BitsToBFloat16(0x8000), BFloat16.Epsilon }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN }; + yield return new object[] { UInt16BitsToBFloat16(0x0000), BFloat16.Epsilon }; + yield return new object[] { UInt16BitsToBFloat16(0x3EA3), UInt16BitsToBFloat16(0x3EA4) }; // value: (1 / pi) + yield return new object[] { UInt16BitsToBFloat16(0x3EDE), UInt16BitsToBFloat16(0x3EDF) }; // value: (log10(e)) + yield return new object[] { UInt16BitsToBFloat16(0x3F23), UInt16BitsToBFloat16(0x3F24) }; // value: (2 / pi) + yield return new object[] { UInt16BitsToBFloat16(0x3F31), UInt16BitsToBFloat16(0x3F32) }; // value: (ln(2)) + yield return new object[] { UInt16BitsToBFloat16(0x3F35), UInt16BitsToBFloat16(0x3F36) }; // value: (1 / sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0x3F49), UInt16BitsToBFloat16(0x3F4A) }; // value: (pi / 4) + yield return new object[] { UInt16BitsToBFloat16(0x3F80), UInt16BitsToBFloat16(0x3F81) }; + yield return new object[] { UInt16BitsToBFloat16(0x3F90), UInt16BitsToBFloat16(0x3F91) }; // value: (2 / sqrt(pi)) + yield return new object[] { UInt16BitsToBFloat16(0x3FB5), UInt16BitsToBFloat16(0x3FB6) }; // value: (sqrt(2)) + yield return new object[] { UInt16BitsToBFloat16(0x3FB9), UInt16BitsToBFloat16(0x3FBA) }; // value: (log2(e)) + yield return new object[] { UInt16BitsToBFloat16(0x3FC9), UInt16BitsToBFloat16(0x3FCA) }; // value: (pi / 2) + yield return new object[] { UInt16BitsToBFloat16(0x4013), UInt16BitsToBFloat16(0x4014) }; // value: (ln(10)) + yield return new object[] { UInt16BitsToBFloat16(0x402E), UInt16BitsToBFloat16(0x402F) }; // value: (e) + yield return new object[] { UInt16BitsToBFloat16(0x4049), UInt16BitsToBFloat16(0x404A) }; // value: (pi) + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity }; + } + + [Theory] + [MemberData(nameof(BitIncrement_TestData))] + public static void BitIncrement(BFloat16 value, BFloat16 expectedResult) + { + AssertEqual(expectedResult, BFloat16.BitIncrement(value), BFloat16.Zero); + } + + public static IEnumerable Lerp_TestData() + { + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NegativeInfinity, (BFloat16)(0.5f), BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.NegativeInfinity, BFloat16.PositiveInfinity, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(0.0f), (BFloat16)(0.5f), BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(1.0f), (BFloat16)(0.5f), BFloat16.NegativeInfinity }; + yield return new object[] { BFloat16.NaN, BFloat16.NegativeInfinity, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, BFloat16.PositiveInfinity, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, (BFloat16)(0.0f), (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.NaN, (BFloat16)(1.0f), (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NegativeInfinity, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, (BFloat16)(0.5f), BFloat16.NaN }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)(0.5f), BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.PositiveInfinity, (BFloat16)(0.0f), (BFloat16)(0.5f), BFloat16.PositiveInfinity }; + yield return new object[] { BFloat16.PositiveInfinity, (BFloat16)(1.0f), (BFloat16)(0.5f), BFloat16.PositiveInfinity }; + yield return new object[] { (BFloat16)(1.0f), (BFloat16)(3.0f), (BFloat16)(0.0f), (BFloat16)(1.0f) }; + yield return new object[] { (BFloat16)(1.0f), (BFloat16)(3.0f), (BFloat16)(0.5f), (BFloat16)(2.0f) }; + yield return new object[] { (BFloat16)(1.0f), (BFloat16)(3.0f), (BFloat16)(1.0f), (BFloat16)(3.0f) }; + yield return new object[] { (BFloat16)(1.0f), (BFloat16)(3.0f), (BFloat16)(2.0f), (BFloat16)(5.0f) }; + yield return new object[] { (BFloat16)(2.0f), (BFloat16)(4.0f), (BFloat16)(0.0f), (BFloat16)(2.0f) }; + yield return new object[] { (BFloat16)(2.0f), (BFloat16)(4.0f), (BFloat16)(0.5f), (BFloat16)(3.0f) }; + yield return new object[] { (BFloat16)(2.0f), (BFloat16)(4.0f), (BFloat16)(1.0f), (BFloat16)(4.0f) }; + yield return new object[] { (BFloat16)(2.0f), (BFloat16)(4.0f), (BFloat16)(2.0f), (BFloat16)(6.0f) }; + yield return new object[] { (BFloat16)(3.0f), (BFloat16)(1.0f), (BFloat16)(0.0f), (BFloat16)(3.0f) }; + yield return new object[] { (BFloat16)(3.0f), (BFloat16)(1.0f), (BFloat16)(0.5f), (BFloat16)(2.0f) }; + yield return new object[] { (BFloat16)(3.0f), (BFloat16)(1.0f), (BFloat16)(1.0f), (BFloat16)(1.0f) }; + yield return new object[] { (BFloat16)(3.0f), (BFloat16)(1.0f), (BFloat16)(2.0f), -(BFloat16)(1.0f) }; + yield return new object[] { (BFloat16)(4.0f), (BFloat16)(2.0f), (BFloat16)(0.0f), (BFloat16)(4.0f) }; + yield return new object[] { (BFloat16)(4.0f), (BFloat16)(2.0f), (BFloat16)(0.5f), (BFloat16)(3.0f) }; + yield return new object[] { (BFloat16)(4.0f), (BFloat16)(2.0f), (BFloat16)(1.0f), (BFloat16)(2.0f) }; + yield return new object[] { (BFloat16)(4.0f), (BFloat16)(2.0f), (BFloat16)(2.0f), (BFloat16)(0.0f) }; + } + + [Theory] + [MemberData(nameof(Lerp_TestData))] + public static void LerpTest(BFloat16 value1, BFloat16 value2, BFloat16 amount, BFloat16 expectedResult) + { + AssertEqual(+expectedResult, BFloat16.Lerp(+value1, +value2, amount), BFloat16.Zero); + AssertEqual((expectedResult == BFloat16.Zero) ? expectedResult : -expectedResult, BFloat16.Lerp(-value1, -value2, amount), BFloat16.Zero); + } + + public static IEnumerable DegreesToRadians_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)(0.3184f), (BFloat16)(0.005554f), CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.4343f), (BFloat16)(0.00758f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.5f), (BFloat16)(0.00872f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.6367f), (BFloat16)(0.01111f), CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.6934f), (BFloat16)(0.0121f), CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)(0.01234f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.785f), (BFloat16)(0.0137f), CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)(1.0f), (BFloat16)(0.01744f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(1.128f), (BFloat16)(0.01968f), CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)(0.02467f), CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.442f), (BFloat16)(0.02518f), CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.5f), (BFloat16)(0.02617f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(1.57f), (BFloat16)(0.0274f), CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.0f), (BFloat16)(0.03488f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(2.303f), (BFloat16)(0.04016f), CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.5f), (BFloat16)(0.0436f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(2.719f), (BFloat16)(0.04742f), CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)(3.0f), (BFloat16)(0.05234f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(3.14f), (BFloat16)(0.0548f), CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)(3.5f), (BFloat16)(0.06107f), CrossPlatformMachineEpsilon }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(DegreesToRadians_TestData))] + public static void DegreesToRadiansTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.DegreesToRadians(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.DegreesToRadians(+value), allowedVariance); + } + + public static IEnumerable RadiansToDegrees_TestData() + { + yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; + yield return new object[] { (BFloat16)(0.005554f), (BFloat16)(0.3184f), CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.00758f), (BFloat16)(0.4343f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.00872f), (BFloat16)(0.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.01111f), (BFloat16)(0.6367f), CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.0121f), (BFloat16)(0.6934f), CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.01234f), (BFloat16)(0.707f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.0137f), (BFloat16)(0.785f), CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)(0.01744f), (BFloat16)(1.0f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.01968f), (BFloat16)(1.128f), CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(0.02467f), (BFloat16)(1.414f), CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(0.02518f), (BFloat16)(1.442f), CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)(0.02617f), (BFloat16)(1.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.0274f), (BFloat16)(1.57f), CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)(0.03488f), (BFloat16)(2.0f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.04016f), (BFloat16)(2.303f), CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)(0.0436f), (BFloat16)(2.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.04742f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)(0.05234f), (BFloat16)(3.0f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.0548f), (BFloat16)(3.14f), CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)(0.06107f), (BFloat16)(3.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, BFloat16.Zero }; + } + + [Theory] + [MemberData(nameof(RadiansToDegrees_TestData))] + public static void RadiansToDegreesTest(BFloat16 value, BFloat16 expectedResult, BFloat16 allowedVariance) + { + AssertEqual(-expectedResult, BFloat16.RadiansToDegrees(-value), allowedVariance); + AssertEqual(+expectedResult, BFloat16.RadiansToDegrees(+value), allowedVariance); + } + + #region AssertExtentions + static bool IsNegativeZero(BFloat16 value) + { + return BFloat16ToUInt16Bits(value) == 0x8000; + } + + static bool IsPositiveZero(BFloat16 value) + { + return BFloat16ToUInt16Bits(value) == 0; + } + + static string ToStringPadded(BFloat16 value) + { + if (BFloat16.IsNaN(value)) + { + return "NaN".PadLeft(5); + } + else if (BFloat16.IsPositiveInfinity(value)) + { + return "+\u221E".PadLeft(5); + } + else if (BFloat16.IsNegativeInfinity(value)) + { + return "-\u221E".PadLeft(5); + } + else if (IsNegativeZero(value)) + { + return "-0.0".PadLeft(5); + } + else if (IsPositiveZero(value)) + { + return "+0.0".PadLeft(5); + } + else + { + return $"{value,5:G5}"; + } + } + + /// Verifies that two values's binary representations are identical. + /// The expected value + /// The value to be compared against + /// Thrown when the representations are not identical + private static void AssertEqual(BFloat16 expected, BFloat16 actual) + { + if (BFloat16ToUInt16Bits(expected) == BFloat16ToUInt16Bits(actual)) + { + return; + } + + if (PlatformDetection.IsRiscV64Process && BFloat16.IsNaN(expected) && BFloat16.IsNaN(actual)) + { + // RISC-V does not preserve payload + return; + } + + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + /// Verifies that two values are equal, within the . + /// The expected value + /// The value to be compared against + /// The total variance allowed between the expected and actual results. + /// Thrown when the values are not equal + private static void AssertEqual(BFloat16 expected, BFloat16 actual, BFloat16 variance) + { + if (BFloat16.IsNaN(expected)) + { + if (BFloat16.IsNaN(actual)) + { + return; + } + + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + else if (BFloat16.IsNaN(actual)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + if (BFloat16.IsNegativeInfinity(expected)) + { + if (BFloat16.IsNegativeInfinity(actual)) + { + return; + } + + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + else if (BFloat16.IsNegativeInfinity(actual)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + if (BFloat16.IsPositiveInfinity(expected)) + { + if (BFloat16.IsPositiveInfinity(actual)) + { + return; + } + + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + else if (BFloat16.IsPositiveInfinity(actual)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + if (IsNegativeZero(expected)) + { + if (IsNegativeZero(actual)) + { + return; + } + + if (IsPositiveZero(variance) || IsNegativeZero(variance)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + // When the variance is not +-0.0, then we are handling a case where + // the actual result is expected to not be exactly -0.0 on some platforms + // and we should fallback to checking if it is within the allowed variance instead. + } + else if (IsNegativeZero(actual)) + { + if (IsPositiveZero(variance) || IsNegativeZero(variance)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + // When the variance is not +-0.0, then we are handling a case where + // the actual result is expected to not be exactly -0.0 on some platforms + // and we should fallback to checking if it is within the allowed variance instead. + } + + if (IsPositiveZero(expected)) + { + if (IsPositiveZero(actual)) + { + return; + } + + if (IsPositiveZero(variance) || IsNegativeZero(variance)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + // When the variance is not +-0.0, then we are handling a case where + // the actual result is expected to not be exactly +0.0 on some platforms + // and we should fallback to checking if it is within the allowed variance instead. + } + else if (IsPositiveZero(actual)) + { + if (IsPositiveZero(variance) || IsNegativeZero(variance)) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + + // When the variance is not +-0.0, then we are handling a case where + // the actual result is expected to not be exactly +0.0 on some platforms + // and we should fallback to checking if it is within the allowed variance instead. + } + + BFloat16 delta = (BFloat16)Math.Abs((float)actual - (float)expected); + + if (delta > variance) + { + throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); + } + } + #endregion } } From dfd49c8833ab49cac8b0aec5b01bafd6f3eec552 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 11 Jun 2024 00:54:53 +0800 Subject: [PATCH 52/67] Convert the precesion of test cases. --- .../System/Numerics/BFloat16Tests.cs | 785 +++++++++--------- 1 file changed, 392 insertions(+), 393 deletions(-) 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 50f999e479c840..af764c7c887ba5 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 @@ -1250,37 +1250,37 @@ public static void MinNumberTest(BFloat16 x, BFloat16 y, BFloat16 expectedResult public static IEnumerable ExpM1_TestData() { yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(-0.956786082f), CrossPlatformMachineEpsilon }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(-0.934011964f), CrossPlatformMachineEpsilon }; // value: -(e) - yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(-0.9f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) - yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(-0.792120424f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) - yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(-0.763709912f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) - yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(-0.756883266f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) - yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(-0.676442736f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) - yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.632120559f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(-0.544061872f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(-0.506931309f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(-0.5f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) - yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(-0.470922192f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(-0.352278515f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(-0.272622651f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-3.141f), (BFloat16)(-0.957f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), (BFloat16)(-0.9336f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.297f), (BFloat16)(-0.8984f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57f), (BFloat16)(-0.793f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.445f), (BFloat16)(-0.7656f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.414f), (BFloat16)(-0.7578f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.125f), (BFloat16)(-0.6758f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.6328f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(-0.7852f), (BFloat16)(-0.543f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707f), (BFloat16)(-0.5078f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.6914f), (BFloat16)(-0.5f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.6367f), (BFloat16)(-0.4707f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.4336f), (BFloat16)(-0.3516f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.3184f), (BFloat16)(-0.2734f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(0.374802227f), CrossPlatformMachineEpsilon }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(0.543873444f), CrossPlatformMachineEpsilon }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(0.890081165f), CrossPlatformMachineEpsilon }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(1.02811498f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(1.19328005f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) - yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(1.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(2.09064302f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(3.11325038f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(3.23208611f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) - yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(3.81047738f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) - yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(9.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) - yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(14.1542622f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (e) - yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(22.1406926f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi) + yield return new object[] { (BFloat16)(0.3184f), (BFloat16)(0.375f), CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.4336f), (BFloat16)(0.543f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.6367f), (BFloat16)(0.8906f), CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.6914f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)(1.031f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7852f), (BFloat16)(1.195f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(1.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(1.125f), (BFloat16)(2.078f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)(3.109f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.445f), (BFloat16)(3.25f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57f), (BFloat16)(3.812f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.297f), (BFloat16)(8.938f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.719f), (BFloat16)(14.19f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (e) + yield return new object[] { (BFloat16)(3.141f), (BFloat16)(22.12f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0.0 }; } @@ -1294,37 +1294,37 @@ public static void ExpM1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 a public static IEnumerable Exp2_TestData() { yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(0.113314732f), CrossPlatformMachineEpsilon }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(0.151955223f), CrossPlatformMachineEpsilon }; // value: -(e) - yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(0.202699566f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) - yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(0.336622537f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) - yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(0.367879441f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) - yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(0.375214227f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) - yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(0.457429347f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-3.141f), (BFloat16)(0.1133f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), (BFloat16)(0.1523f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.297f), (BFloat16)(0.2031f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57f), (BFloat16)(0.3359f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.445f), (BFloat16)(0.3672f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.414f), (BFloat16)(0.375f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.125f), (BFloat16)(0.459f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(0.5f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(0.580191810f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(0.612547327f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(0.618503138f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) - yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(0.643218242f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(0.740055574f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(0.802008879f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.7852f), (BFloat16)(0.582f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707f), (BFloat16)(0.6133f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.6914f), (BFloat16)(0.6211f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.6367f), (BFloat16)(0.6445f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.4336f), (BFloat16)(0.7422f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.3184f), (BFloat16)(0.8008f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(BFloat16.One), (BFloat16)0.0f }; yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { (BFloat16)(0.0f), (BFloat16)(BFloat16.One), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(1.24686899f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(1.35124987f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(1.55468228f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(1.61680667f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(1.63252692f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(1.72356793f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(0.3184f), (BFloat16)(1.25f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.4336f), (BFloat16)(1.352f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.6367f), (BFloat16)(1.555f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.6914f), (BFloat16)(1.617f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)(1.633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7852f), (BFloat16)(1.727f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(2.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(2.18612996f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(2.66514414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) - yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(2.97068642f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) - yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(4.93340967f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) - yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(6.58088599f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) - yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(8.82497783f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi) + yield return new object[] { (BFloat16)(1.125f), (BFloat16)(2.188f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)(2.672f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.445f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57f), (BFloat16)(2.969f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.297f), (BFloat16)(4.906f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.719f), (BFloat16)(6.594f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) + yield return new object[] { (BFloat16)(3.141f), (BFloat16)(8.812f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, 0.0f }; } @@ -1338,37 +1338,37 @@ public static void Exp2Test(BFloat16 value, BFloat16 expectedResult, BFloat16 al public static IEnumerable Exp2M1_TestData() { yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(-BFloat16.One), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(-0.886685268f), CrossPlatformMachineEpsilon }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(-0.848044777f), CrossPlatformMachineEpsilon }; // value: -(e) - yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(-0.797300434f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) - yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(-0.663377463f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) - yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(-0.632120559f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) - yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(-0.624785773f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) - yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(-0.542570653f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-3.141f), (BFloat16)(-0.8867f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), (BFloat16)(-0.8477f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.297f), (BFloat16)(-0.7969f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57f), (BFloat16)(-0.6641f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.445f), (BFloat16)(-0.6328f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.414f), (BFloat16)(-0.625f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.125f), (BFloat16)(-0.543f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.5f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(-0.419808190f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(-0.387452673f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(-0.381496862f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) - yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(-0.356781758f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(-0.259944426f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(-0.197991121f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) - yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-0.7852f), (BFloat16)(-0.4199f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707f), (BFloat16)(-0.3867f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.6914f), (BFloat16)(-0.3809f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.6367f), (BFloat16)(-0.3574f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.4336f), (BFloat16)(-0.2598f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.3184f), (BFloat16)(-0.1982f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0f), (BFloat16)(0f), (BFloat16)0.0f }; yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(0.246868989f), CrossPlatformMachineEpsilon }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(0.351249873f), CrossPlatformMachineEpsilon }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(0.554682275f), CrossPlatformMachineEpsilon }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(0.616806672f), CrossPlatformMachineEpsilon }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(0.632526919f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(0.723567934f), CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)(0f), (BFloat16)(0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.3184f), (BFloat16)(0.2471f), CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.4336f), (BFloat16)(0.3516f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.6367f), (BFloat16)(0.5547f), CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.6914f), (BFloat16)(0.6133f), CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)(0.6328f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7852f), (BFloat16)(0.7227f), CrossPlatformMachineEpsilon }; // value: (pi / 4) yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(1.18612996f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(1.66514414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(1.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) - yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(1.97068642f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) - yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(3.93340967f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) - yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(5.58088599f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) - yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(7.82497783f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi) + yield return new object[] { (BFloat16)(1.125f), (BFloat16)(1.18f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)(1.664f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.445f), (BFloat16)(1.727f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57f), (BFloat16)(1.969f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.297f), (BFloat16)(3.906f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.719f), (BFloat16)(5.594f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) + yield return new object[] { (BFloat16)(3.141f), (BFloat16)(7.812f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; } @@ -1382,37 +1382,37 @@ public static void Exp2M1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 public static IEnumerable Exp10_TestData() { yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)0.0f, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)0.000721784159f, CrossPlatformMachineEpsilon / (BFloat16)1000 }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)0.00191301410f, CrossPlatformMachineEpsilon / (BFloat16)100 }; // value: -(e) - yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)0.00498212830f, CrossPlatformMachineEpsilon / (BFloat16)100 }; // value: -(ln(10)) - yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)0.0268660410f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(pi / 2) - yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)0.0360831928f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(log2(e)) - yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)0.0385288847f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(sqrt(2)) - yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)0.0744082059f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-3.141f), (BFloat16)0.0007248f, CrossPlatformMachineEpsilon / (BFloat16)1000 }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), (BFloat16)0.001907f, CrossPlatformMachineEpsilon / (BFloat16)100 }; // value: -(e) + yield return new object[] { (BFloat16)(-2.297f), (BFloat16)0.005035f, CrossPlatformMachineEpsilon / (BFloat16)100 }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57f), (BFloat16)0.02686f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.445f), (BFloat16)0.03589f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.414f), (BFloat16)0.03857f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.125f), (BFloat16)0.0752f, CrossPlatformMachineEpsilon / (BFloat16)10 }; // value: -(2 / sqrt(pi)) yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)0.1f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)0.163908636f, CrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)0.196287760f, CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)0.202699566f, CrossPlatformMachineEpsilon }; // value: -(ln(2)) - yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)0.230876765f, CrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)0.367879441f, CrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)0.480496373f, CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0.7852f), (BFloat16)0.1641f, CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707f), (BFloat16)0.1963f, CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.6914f), (BFloat16)0.2031f, CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.6367f), (BFloat16)0.2305f, CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.4336f), (BFloat16)0.3691f, CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.3184f), (BFloat16)0.4805f, CrossPlatformMachineEpsilon }; // value: -(1 / pi) yield return new object[] { (BFloat16)(-0.0f), (BFloat16)BFloat16.One, (BFloat16)0.0f }; yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { (BFloat16)(0.0f), (BFloat16)BFloat16.One, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)2.08118116f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)2.71828183f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)4.33131503f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)4.93340967f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)5.09456117f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)6.10095980f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(0.3184f), (BFloat16)2.078f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.4336f), (BFloat16)2.719f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.6367f), (BFloat16)4.344f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.6914f), (BFloat16)4.906f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)5.094f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7852f), (BFloat16)6.094f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; - yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)13.4393779f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)25.9545535f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)27.7137338f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (log2(e)) - yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)37.2217105f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi / 2) - yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)200.717432f, CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (ln(10)) - yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)522.735300f, CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (e) - yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)1385.45573f, CrossPlatformMachineEpsilon * (BFloat16)10000 }; // value: (pi) + yield return new object[] { (BFloat16)(1.125f), (BFloat16)13.31f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)26f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.445f), (BFloat16)27.88f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57f), (BFloat16)37.25f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.297f), (BFloat16)198f, CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.719f), (BFloat16)524f, CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (e) + yield return new object[] { (BFloat16)(3.141f), (BFloat16)1384f, CrossPlatformMachineEpsilon * (BFloat16)10000 }; // value: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; } @@ -1426,37 +1426,37 @@ public static void Exp10Test(BFloat16 value, BFloat16 expectedResult, BFloat16 a public static IEnumerable Exp10M1_TestData() { yield return new object[] { BFloat16.NegativeInfinity, (BFloat16)(-BFloat16.One), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-3.14159265f), (BFloat16)(-0.999278216f), CrossPlatformMachineEpsilon }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), (BFloat16)(-0.998086986f), CrossPlatformMachineEpsilon }; // value: -(e) - yield return new object[] { (BFloat16)(-2.30258509f), (BFloat16)(-0.995017872f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) - yield return new object[] { (BFloat16)(-1.57079633f), (BFloat16)(-0.973133959f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) - yield return new object[] { (BFloat16)(-1.44269504f), (BFloat16)(-0.963916807f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) - yield return new object[] { (BFloat16)(-1.41421356f), (BFloat16)(-0.961471115f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) - yield return new object[] { (BFloat16)(-1.12837917f), (BFloat16)(-0.925591794f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-3.141f), (BFloat16)(-1f), CrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), (BFloat16)(-1f), CrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { (BFloat16)(-2.297f), (BFloat16)(-0.9961f), CrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { (BFloat16)(-1.57f), (BFloat16)(-0.9727f), CrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { (BFloat16)(-1.445f), (BFloat16)(-0.9648f), CrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { (BFloat16)(-1.414f), (BFloat16)(-0.9609f), CrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-1.125f), (BFloat16)(-0.9258f), CrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) yield return new object[] { (BFloat16)(-BFloat16.One), (BFloat16)(-0.9f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(-0.785398163f), (BFloat16)(-0.836091364f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { (BFloat16)(-0.707106781f), (BFloat16)(-0.803712240f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.693147181f), (BFloat16)(-0.797300434f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) - yield return new object[] { (BFloat16)(-0.636619772f), (BFloat16)(-0.769123235f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { (BFloat16)(-0.434294482f), (BFloat16)(-0.632120559f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { (BFloat16)(-0.318309886f), (BFloat16)(-0.519503627f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) - yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(-0.7852f), (BFloat16)(-0.8359f), CrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { (BFloat16)(-0.707f), (BFloat16)(-0.8047f), CrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.6914f), (BFloat16)(-0.7969f), CrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { (BFloat16)(-0.6367f), (BFloat16)(-0.7695f), CrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { (BFloat16)(-0.4336f), (BFloat16)(-0.6328f), CrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { (BFloat16)(-0.3184f), (BFloat16)(-0.5195f), CrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { (BFloat16)(-0f), (BFloat16)(0f), (BFloat16)0.0f }; yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.318309886f), (BFloat16)(1.08118116f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.434294482f), (BFloat16)(1.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.636619772f), (BFloat16)(3.33131503f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.693147181f), (BFloat16)(3.93340967f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.707106781f), (BFloat16)(4.09456117f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.785398163f), (BFloat16)(5.10095980f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) + yield return new object[] { (BFloat16)(0f), (BFloat16)(0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.3184f), (BFloat16)(1.078f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)(0.4336f), (BFloat16)(1.711f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.6367f), (BFloat16)(3.328f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)(0.6914f), (BFloat16)(3.906f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)(4.094f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7852f), (BFloat16)(5.094f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 4) yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(9.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(1.12837917f), (BFloat16)(12.4393779f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.41421356f), (BFloat16)(24.9545535f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(1.44269504f), (BFloat16)(26.7137338f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (log2(e)) - yield return new object[] { (BFloat16)(1.57079633f), (BFloat16)(36.2217105f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi / 2) - yield return new object[] { (BFloat16)(2.30258509f), (BFloat16)(199.717432f), CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (ln(10)) - yield return new object[] { (BFloat16)(2.71828183f), (BFloat16)(521.735300f), CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (e) - yield return new object[] { (BFloat16)(3.14159265f), (BFloat16)(1384.45573f), CrossPlatformMachineEpsilon * (BFloat16)10000 }; // value: (pi) + yield return new object[] { (BFloat16)(1.125f), (BFloat16)(12.31f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)(25f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.445f), (BFloat16)(26.88f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.57f), (BFloat16)(36.25f), CrossPlatformMachineEpsilon * (BFloat16)100 }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.297f), (BFloat16)(197f), CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.719f), (BFloat16)(524f), CrossPlatformMachineEpsilon * (BFloat16)1000 }; // value: (e) + yield return new object[] { (BFloat16)(3.141f), (BFloat16)(1384f), CrossPlatformMachineEpsilon * (BFloat16)10000 }; // value: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; } @@ -1470,39 +1470,39 @@ public static void Exp10M1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 public static IEnumerable LogP1_TestData() { yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-3.14159265f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(e) - yield return new object[] { (BFloat16)(-1.41421356f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-3.141f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(e) + yield return new object[] { (BFloat16)(-1.414f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(sqrt(2)) yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { (BFloat16)(-BFloat16.One), BFloat16.NegativeInfinity, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-0.956786082f), (BFloat16)(-3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi) - yield return new object[] { (BFloat16)(-0.934011964f), (BFloat16)(-2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) - yield return new object[] { (BFloat16)(-0.9f), (BFloat16)(-2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) - yield return new object[] { (BFloat16)(-0.792120424f), (BFloat16)(-1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) - yield return new object[] { (BFloat16)(-0.763709912f), (BFloat16)(-1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) - yield return new object[] { (BFloat16)(-0.756883266f), (BFloat16)(-1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) - yield return new object[] { (BFloat16)(-0.676442736f), (BFloat16)(-1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { (BFloat16)(-0.632120559f), (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(-0.544061872f), (BFloat16)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { (BFloat16)(-0.506931309f), (BFloat16)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.5f), (BFloat16)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { (BFloat16)(-0.470922192f), (BFloat16)(-0.636619772f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), 0.0f }; - yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), 0.0f }; - yield return new object[] { (BFloat16)(0.374802227f), (BFloat16)(0.318309886f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { (BFloat16)(0.543873444f), (BFloat16)(0.434294482f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) - yield return new object[] { (BFloat16)(0.890081165f), (BFloat16)(0.636619772f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(0.693147181f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { (BFloat16)(1.02811498f), (BFloat16)(0.707106781f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(1.19328005f), (BFloat16)(0.785398163f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) - yield return new object[] { (BFloat16)(1.71828183f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(2.09064302f), (BFloat16)(1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(3.11325038f), (BFloat16)(1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) - yield return new object[] { (BFloat16)(3.23208611f), (BFloat16)(1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) - yield return new object[] { (BFloat16)(3.81047738f), (BFloat16)(1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) - yield return new object[] { (BFloat16)(9.0f), (BFloat16)(2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) - yield return new object[] { (BFloat16)(14.1542622f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) - yield return new object[] { (BFloat16)(22.1406926f), (BFloat16)(3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) + yield return new object[] { (BFloat16)(-0.957f), (BFloat16)(-3.141f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi) + yield return new object[] { (BFloat16)(-0.9336f), (BFloat16)(-2.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) + yield return new object[] { (BFloat16)(-0.8984f), (BFloat16)(-2.281f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) + yield return new object[] { (BFloat16)(-0.793f), (BFloat16)(-1.578f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) + yield return new object[] { (BFloat16)(-0.7656f), (BFloat16)(-1.453f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) + yield return new object[] { (BFloat16)(-0.7578f), (BFloat16)(-1.422f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) + yield return new object[] { (BFloat16)(-0.6758f), (BFloat16)(-1.125f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-0.6321f), (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(-0.543f), (BFloat16)(-0.7812f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { (BFloat16)(-0.5078f), (BFloat16)(-0.707f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.5f), (BFloat16)(-0.6914f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { (BFloat16)(-0.4707f), (BFloat16)(-0.6367f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { (BFloat16)(-0f), (BFloat16)(0f), 0.0f }; + yield return new object[] { (BFloat16)(0f), (BFloat16)(0f), 0.0f }; + yield return new object[] { (BFloat16)(0.375f), (BFloat16)(0.3184f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { (BFloat16)(0.543f), (BFloat16)(0.4336f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { (BFloat16)(0.8906f), (BFloat16)(0.6367f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(0.6931f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { (BFloat16)(1.031f), (BFloat16)(0.707f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(1.195f), (BFloat16)(0.7852f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { (BFloat16)(1.719f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(2.094f), (BFloat16)(1.133f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(3.109f), (BFloat16)(1.414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) + yield return new object[] { (BFloat16)(3.234f), (BFloat16)(1.445f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) + yield return new object[] { (BFloat16)(3.812f), (BFloat16)(1.57f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) + yield return new object[] { (BFloat16)(9f), (BFloat16)(2.297f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) + yield return new object[] { (BFloat16)(14.12f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) + yield return new object[] { (BFloat16)(22.12f), (BFloat16)(3.141f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; } @@ -1518,36 +1518,36 @@ public static IEnumerable Log2P1_TestData() yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { (BFloat16)(-BFloat16.One), BFloat16.NegativeInfinity, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-0.886685268f), (BFloat16)(-3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi) - yield return new object[] { (BFloat16)(-0.848044777f), (BFloat16)(-2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) - yield return new object[] { (BFloat16)(-0.797300434f), (BFloat16)(-2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) - yield return new object[] { (BFloat16)(-0.663377463f), (BFloat16)(-1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) - yield return new object[] { (BFloat16)(-0.632120559f), (BFloat16)(-1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) - yield return new object[] { (BFloat16)(-0.624785773f), (BFloat16)(-1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) - yield return new object[] { (BFloat16)(-0.542570653f), (BFloat16)(-1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-0.8867f), (BFloat16)(-3.141f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi) + yield return new object[] { (BFloat16)(-0.8477f), (BFloat16)(-2.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) + yield return new object[] { (BFloat16)(-0.7969f), (BFloat16)(-2.297f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) + yield return new object[] { (BFloat16)(-0.6641f), (BFloat16)(-1.57f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) + yield return new object[] { (BFloat16)(-0.6328f), (BFloat16)(-1.445f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) + yield return new object[] { (BFloat16)(-0.625f), (BFloat16)(-1.414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) + yield return new object[] { (BFloat16)(-0.543f), (BFloat16)(-1.133f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) yield return new object[] { (BFloat16)(-0.5f), (BFloat16)(-BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(-0.419808190f), (BFloat16)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { (BFloat16)(-0.387452673f), (BFloat16)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.381496862f), (BFloat16)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { (BFloat16)(-0.356781758f), (BFloat16)(-0.636619772f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { (BFloat16)(-0.259944426f), (BFloat16)(-0.434294482f), CrossPlatformMachineEpsilon }; // expected: -(log10(e)) - yield return new object[] { (BFloat16)(-0.197991121f), (BFloat16)(-0.318309886f), CrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.246868989f), (BFloat16)(0.318309886f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { (BFloat16)(0.351249873f), (BFloat16)(0.434294482f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) - yield return new object[] { (BFloat16)(0.554682275f), (BFloat16)(0.636619772f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { (BFloat16)(0.616806672f), (BFloat16)(0.693147181f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { (BFloat16)(0.632526919f), (BFloat16)(0.707106781f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.723567934f), (BFloat16)(0.785398163f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { (BFloat16)(-0.4199f), (BFloat16)(-0.7852f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { (BFloat16)(-0.3867f), (BFloat16)(-0.707f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.3809f), (BFloat16)(-0.6914f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { (BFloat16)(-0.3574f), (BFloat16)(-0.6367f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { (BFloat16)(-0.2598f), (BFloat16)(-0.4336f), CrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { (BFloat16)(-0.1982f), (BFloat16)(-0.3184f), CrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { (BFloat16)(-0f), (BFloat16)(0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0f), (BFloat16)(0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0.2471f), (BFloat16)(0.3184f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { (BFloat16)(0.3516f), (BFloat16)(0.4355f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { (BFloat16)(0.5547f), (BFloat16)(0.6367f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { (BFloat16)(0.6172f), (BFloat16)(0.6953f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { (BFloat16)(0.6328f), (BFloat16)(0.707f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7227f), (BFloat16)(0.7852f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) yield return new object[] { (BFloat16)(BFloat16.One), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(1.18612996f), (BFloat16)(1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.66514414f), (BFloat16)(1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) - yield return new object[] { (BFloat16)(1.71828183f), (BFloat16)(1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) - yield return new object[] { (BFloat16)(1.97068642f), (BFloat16)(1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) - yield return new object[] { (BFloat16)(3.93340967f), (BFloat16)(2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) - yield return new object[] { (BFloat16)(5.58088599f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) - yield return new object[] { (BFloat16)(7.82497783f), (BFloat16)(3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) + yield return new object[] { (BFloat16)(1.188f), (BFloat16)(1.133f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.664f), (BFloat16)(1.414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) + yield return new object[] { (BFloat16)(1.719f), (BFloat16)(1.445f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) + yield return new object[] { (BFloat16)(1.969f), (BFloat16)(1.57f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) + yield return new object[] { (BFloat16)(3.938f), (BFloat16)(2.297f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) + yield return new object[] { (BFloat16)(5.594f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) + yield return new object[] { (BFloat16)(7.812f), (BFloat16)(3.141f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; } @@ -1561,40 +1561,39 @@ public static void Log2P1Test(BFloat16 value, BFloat16 expectedResult, BFloat16 public static IEnumerable Log10P1_TestData() { yield return new object[] { BFloat16.NegativeInfinity, BFloat16.NaN, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-3.14159265f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(pi) - yield return new object[] { (BFloat16)(-2.71828183f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(e) - yield return new object[] { (BFloat16)(-1.41421356f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(sqrt(2)) + yield return new object[] { (BFloat16)(-3.141f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(pi) + yield return new object[] { (BFloat16)(-2.719f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(e) + yield return new object[] { (BFloat16)(-1.414f), BFloat16.NaN, (BFloat16)0.0f }; // value: -(sqrt(2)) yield return new object[] { BFloat16.NaN, BFloat16.NaN, (BFloat16)0.0f }; yield return new object[] { (BFloat16)(-BFloat16.One), BFloat16.NegativeInfinity, (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(-0.998086986f), (BFloat16)(-2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(e) - yield return new object[] { (BFloat16)(-0.995017872f), (BFloat16)(-2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) - yield return new object[] { (BFloat16)(-0.973133959f), (BFloat16)(-1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) - yield return new object[] { (BFloat16)(-0.963916807f), (BFloat16)(-1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) - yield return new object[] { (BFloat16)(-0.961471115f), (BFloat16)(-1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) - yield return new object[] { (BFloat16)(-0.925591794f), (BFloat16)(-1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { (BFloat16)(-0.9f), (BFloat16)(-1.0f), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(-0.836091364f), (BFloat16)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { (BFloat16)(-0.803712240f), (BFloat16)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { (BFloat16)(-0.797300434f), (BFloat16)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { (BFloat16)(-0.769123235f), (BFloat16)(-0.636619772f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { (BFloat16)(-0.632120559f), (BFloat16)(-0.434294482f), CrossPlatformMachineEpsilon }; // expected: -(log10(e)) - yield return new object[] { (BFloat16)(-0.519503627f), (BFloat16)(-0.318309886f), CrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { (BFloat16)(-0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(0.0f), (BFloat16)(0.0f), (BFloat16)0.0f }; - yield return new object[] { (BFloat16)(1.08118116f), (BFloat16)(0.318309886f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { (BFloat16)(1.71828183f), (BFloat16)(0.434294482f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) value: (e) - yield return new object[] { (BFloat16)(3.33131503f), (BFloat16)(0.636619772f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { (BFloat16)(3.93340967f), (BFloat16)(0.693147181f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { (BFloat16)(4.09456117f), (BFloat16)(0.707106781f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(5.10095980f), (BFloat16)(0.785398163f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { (BFloat16)(-0.9961f), (BFloat16)(-2.406f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(ln(10)) + yield return new object[] { (BFloat16)(-0.9727f), (BFloat16)(-1.562f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(pi / 2) + yield return new object[] { (BFloat16)(-0.9648f), (BFloat16)(-1.453f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(log2(e)) + yield return new object[] { (BFloat16)(-0.9609f), (BFloat16)(-1.406f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(sqrt(2)) + yield return new object[] { (BFloat16)(-0.9258f), (BFloat16)(-1.133f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { (BFloat16)(-0.8984f), (BFloat16)(-0.9922f), CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { (BFloat16)(-0.8359f), (BFloat16)(-0.7852f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { (BFloat16)(-0.8047f), (BFloat16)(-0.7109f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { (BFloat16)(-0.7969f), (BFloat16)(-0.6914f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { (BFloat16)(-0.7695f), (BFloat16)(-0.6367f), CrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { (BFloat16)(-0.6328f), (BFloat16)(-0.4355f), CrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { (BFloat16)(-0.5195f), (BFloat16)(-0.3184f), CrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { (BFloat16)(-0f), (BFloat16)(0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(0f), (BFloat16)(0f), (BFloat16)0.0f }; + yield return new object[] { (BFloat16)(1.078f), (BFloat16)(0.3184f), CrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { (BFloat16)(1.719f), (BFloat16)(0.4336f), CrossPlatformMachineEpsilon }; // expected: (log10(e)) value: (e) + yield return new object[] { (BFloat16)(3.328f), (BFloat16)(0.6367f), CrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { (BFloat16)(3.938f), (BFloat16)(0.6953f), CrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { (BFloat16)(4.094f), (BFloat16)(0.707f), CrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(5.094f), (BFloat16)(0.7852f), CrossPlatformMachineEpsilon }; // expected: (pi / 4) yield return new object[] { (BFloat16)(9.0f), (BFloat16)(BFloat16.One), CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { (BFloat16)(12.4393779f), (BFloat16)(1.12837917f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(24.9545535f), (BFloat16)(1.41421356f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) - yield return new object[] { (BFloat16)(26.7137338f), (BFloat16)(1.44269504f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) - yield return new object[] { (BFloat16)(36.2217105f), (BFloat16)(1.57079633f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) - yield return new object[] { (BFloat16)(199.717432f), (BFloat16)(2.30258509f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) - yield return new object[] { (BFloat16)(521.735300f), (BFloat16)(2.71828183f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) - yield return new object[] { (BFloat16)(1384.45573f), (BFloat16)(3.14159265f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) + yield return new object[] { (BFloat16)(12.44f), (BFloat16)(1.125f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(25f), (BFloat16)(1.414f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (sqrt(2)) + yield return new object[] { (BFloat16)(26.75f), (BFloat16)(1.445f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (log2(e)) + yield return new object[] { (BFloat16)(36.25f), (BFloat16)(1.57f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi / 2) + yield return new object[] { (BFloat16)(200f), (BFloat16)(2.297f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (ln(10)) + yield return new object[] { (BFloat16)(520f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (e) + yield return new object[] { (BFloat16)(1384f), (BFloat16)(3.141f), CrossPlatformMachineEpsilon * (BFloat16)10 }; // expected: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, (BFloat16)0.0f }; } @@ -1614,40 +1613,40 @@ public static IEnumerable Hypot_TestData() yield return new object[] { BFloat16.NaN, (BFloat16)10.0f, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.One, BFloat16.One, BFloat16.Zero }; - yield return new object[] { BFloat16.Zero, (BFloat16)1.57079633f, (BFloat16)1.57079633f, BFloat16.Zero }; + yield return new object[] { BFloat16.Zero, (BFloat16)1.57f, (BFloat16)1.57f, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, (BFloat16)2.0f, (BFloat16)2.0f, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.E, BFloat16.E, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, (BFloat16)3.0f, (BFloat16)3.0f, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, (BFloat16)10.0f, (BFloat16)10.0f, BFloat16.Zero }; yield return new object[] { BFloat16.One, BFloat16.One, (BFloat16)1.41421356f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, (BFloat16)0.318309886f, (BFloat16)2.73685536f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (1 / pi) - yield return new object[] { BFloat16.E, (BFloat16)0.434294482f, (BFloat16)2.75275640f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (log10(e)) - yield return new object[] { BFloat16.E, (BFloat16)0.636619772f, (BFloat16)2.79183467f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (2 / pi) - yield return new object[] { BFloat16.E, (BFloat16)0.693147181f, (BFloat16)2.80526454f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (ln(2)) - yield return new object[] { BFloat16.E, (BFloat16)0.707106781f, (BFloat16)2.80874636f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (1 / sqrt(2)) - yield return new object[] { BFloat16.E, (BFloat16)0.785398163f, (BFloat16)2.82947104f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi / 4) - yield return new object[] { BFloat16.E, BFloat16.One, (BFloat16)2.89638673f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) - yield return new object[] { BFloat16.E, (BFloat16)1.12837917f, (BFloat16)2.94317781f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (2 / sqrt(pi)) - yield return new object[] { BFloat16.E, (BFloat16)1.41421356f, (BFloat16)3.06415667f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (sqrt(2)) - yield return new object[] { BFloat16.E, (BFloat16)1.44269504f, (BFloat16)3.07740558f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (log2(e)) - yield return new object[] { BFloat16.E, (BFloat16)1.57079633f, (BFloat16)3.13949951f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi / 2) - yield return new object[] { BFloat16.E, (BFloat16)2.30258509f, (BFloat16)3.56243656f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (ln(10)) - yield return new object[] { BFloat16.E, BFloat16.E, (BFloat16)3.84423103f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (e) - yield return new object[] { BFloat16.E, (BFloat16)3.14159265f, (BFloat16)4.15435440f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi) - yield return new object[] { (BFloat16)10.0f, (BFloat16)0.318309886f, (BFloat16)10.0050648f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (1 / pi) - yield return new object[] { (BFloat16)10.0f, (BFloat16)0.434294482f, (BFloat16)10.0094261f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (log10(e)) - yield return new object[] { (BFloat16)10.0f, (BFloat16)0.636619772f, (BFloat16)10.0202437f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (2 / pi) - yield return new object[] { (BFloat16)10.0f, (BFloat16)0.693147181f, (BFloat16)10.0239939f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (ln(2)) - yield return new object[] { (BFloat16)10.0f, (BFloat16)0.707106781f, (BFloat16)10.0249688f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (1 / sqrt(2)) - yield return new object[] { (BFloat16)10.0f, (BFloat16)0.785398163f, (BFloat16)10.0307951f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi / 4) - yield return new object[] { (BFloat16)10.0f, BFloat16.One, (BFloat16)10.0498756f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // - yield return new object[] { (BFloat16)10.0f, (BFloat16)1.12837917f, (BFloat16)10.0634606f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)10.0f, (BFloat16)1.41421356f, (BFloat16)10.0995049f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (sqrt(2)) - yield return new object[] { (BFloat16)10.0f, (BFloat16)1.44269504f, (BFloat16)10.1035325f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (log2(e)) - yield return new object[] { (BFloat16)10.0f, (BFloat16)1.57079633f, (BFloat16)10.1226183f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi / 2) - yield return new object[] { (BFloat16)10.0f, (BFloat16)2.30258509f, (BFloat16)10.2616713f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (ln(10)) - yield return new object[] { (BFloat16)10.0f, BFloat16.E, (BFloat16)10.3628691f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (e) - yield return new object[] { (BFloat16)10.0f, (BFloat16)3.14159265f, (BFloat16)10.4818703f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi) + yield return new object[] { BFloat16.E, (BFloat16)0.3184f, (BFloat16)2.734f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (1 / pi) + yield return new object[] { BFloat16.E, (BFloat16)0.4336f, (BFloat16)2.75f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (log10(e)) + yield return new object[] { BFloat16.E, (BFloat16)0.6367f, (BFloat16)2.797f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (2 / pi) + yield return new object[] { BFloat16.E, (BFloat16)0.6914f, (BFloat16)2.812f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (ln(2)) + yield return new object[] { BFloat16.E, (BFloat16)0.707f, (BFloat16)2.812f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (1 / sqrt(2)) + yield return new object[] { BFloat16.E, (BFloat16)0.7852f, (BFloat16)2.828f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi / 4) + yield return new object[] { BFloat16.E, BFloat16.One, (BFloat16)2.896f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) + yield return new object[] { BFloat16.E, (BFloat16)1.125f, (BFloat16)2.938f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (2 / sqrt(pi)) + yield return new object[] { BFloat16.E, (BFloat16)1.414f, (BFloat16)3.062f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (sqrt(2)) + yield return new object[] { BFloat16.E, (BFloat16)1.445f, (BFloat16)3.078f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (log2(e)) + yield return new object[] { BFloat16.E, (BFloat16)1.57f, (BFloat16)3.141f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi / 2) + yield return new object[] { BFloat16.E, (BFloat16)2.297f, (BFloat16)3.562f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (ln(10)) + yield return new object[] { BFloat16.E, BFloat16.E, (BFloat16)3.844f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (e) + yield return new object[] { BFloat16.E, (BFloat16)3.141f, (BFloat16)4.156f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // x: (e) y: (pi) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.3184f, (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (1 / pi) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.4336f, (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (log10(e)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.6367f, (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (2 / pi) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.6914f, (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (ln(2)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.707f, (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (1 / sqrt(2)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)0.7852f, (BFloat16)10.0f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi / 4) + yield return new object[] { (BFloat16)10.0f, BFloat16.One, (BFloat16)10.05f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.125f, (BFloat16)10.06f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.414f, (BFloat16)10.12f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (sqrt(2)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.445f, (BFloat16)10.12f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (log2(e)) + yield return new object[] { (BFloat16)10.0f, (BFloat16)1.57f, (BFloat16)10.12f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi / 2) + yield return new object[] { (BFloat16)10.0f, (BFloat16)2.297f, (BFloat16)10.25f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (ln(10)) + yield return new object[] { (BFloat16)10.0f, BFloat16.E, (BFloat16)10.36f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (e) + yield return new object[] { (BFloat16)10.0f, (BFloat16)3.141f, (BFloat16)10.5f, CrossPlatformMachineEpsilon * (BFloat16)100 }; // y: (pi) yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.PositiveInfinity, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.Zero, BFloat16.PositiveInfinity, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.One, BFloat16.PositiveInfinity, BFloat16.Zero }; @@ -1750,17 +1749,17 @@ public static IEnumerable RootN_TestData() yield return new object[] { BFloat16.One, 3, BFloat16.One, BFloat16.Zero }; yield return new object[] { BFloat16.One, 4, BFloat16.One, BFloat16.Zero }; yield return new object[] { BFloat16.One, 5, BFloat16.One, BFloat16.Zero }; - yield return new object[] { BFloat16.E, -5, (BFloat16)0.81873075f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, -4, (BFloat16)0.77880078f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, -3, (BFloat16)0.71653131f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, -2, (BFloat16)0.60653066f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, -1, (BFloat16)0.36787944f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -5, (BFloat16)0.8187f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -4, (BFloat16)0.7788f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -3, (BFloat16)0.7165f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -2, (BFloat16)0.6065f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, -1, (BFloat16)0.3679f, CrossPlatformMachineEpsilon * (BFloat16)10 }; yield return new object[] { BFloat16.E, 0, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.E, 1, BFloat16.E, BFloat16.Zero }; - yield return new object[] { BFloat16.E, 2, (BFloat16)1.64872127f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, 3, (BFloat16)1.39561243f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, 4, (BFloat16)1.28402542f, CrossPlatformMachineEpsilon * (BFloat16)10 }; - yield return new object[] { BFloat16.E, 5, (BFloat16)1.22140276f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 2, (BFloat16)1.6487f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 3, (BFloat16)1.3956f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 4, (BFloat16)1.2840f, CrossPlatformMachineEpsilon * (BFloat16)10 }; + yield return new object[] { BFloat16.E, 5, (BFloat16)1.2214f, CrossPlatformMachineEpsilon * (BFloat16)10 }; yield return new object[] { BFloat16.PositiveInfinity, -5, BFloat16.Zero, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, -4, BFloat16.Zero, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, -3, BFloat16.Zero, BFloat16.Zero }; @@ -1785,21 +1784,21 @@ public static IEnumerable AcosPi_TestData() { yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.One, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.540302306f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.204957194f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.5391f, (BFloat16)0.3184f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.2051f, (BFloat16)0.4336f, CrossPlatformMachineEpsilon }; yield return new object[] { BFloat16.Zero, (BFloat16)0.5f, BFloat16.Zero }; - yield return new object[] { -(BFloat16)0.416146837f, (BFloat16)0.636619772f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.570233249f, (BFloat16)0.693147181f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.605699867f, (BFloat16)0.707106781f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.781211892f, (BFloat16)0.785398163f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.416f, (BFloat16)0.6367f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.5703f, (BFloat16)0.6914f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.6055f, (BFloat16)0.707f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.7812f, (BFloat16)0.7852f, CrossPlatformMachineEpsilon }; yield return new object[] { -(BFloat16)1.0f, BFloat16.One, BFloat16.Zero }; - yield return new object[] { -(BFloat16)0.919764995f, (BFloat16)0.871620833f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.266255342f, (BFloat16)0.585786438f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.179057946f, (BFloat16)0.557304959f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.220584041f, (BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.581195664f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.633255651f, (BFloat16)0.718281828f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.902685362f, (BFloat16)0.858407346f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.918f, (BFloat16)0.8711f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.2656f, (BFloat16)0.5859f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.1787f, (BFloat16)0.5586f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.2207f, (BFloat16)0.4297f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.582f, (BFloat16)0.3027f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.6328f, (BFloat16)0.7188f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.9023f, (BFloat16)0.8594f, CrossPlatformMachineEpsilon }; } [Theory] @@ -1813,20 +1812,20 @@ public static IEnumerable AsinPi_TestData() { yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.841470985f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.978770938f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.8398f, (BFloat16)0.3164f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.9805f, (BFloat16)0.4375f, CrossPlatformMachineEpsilon }; yield return new object[] { BFloat16.One, (BFloat16)0.5f, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.909297427f, (BFloat16)0.363380228f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.821482831f, (BFloat16)0.306852819f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.795693202f, (BFloat16)0.292893219f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.624265953f, (BFloat16)0.214601837f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.392469559f, -(BFloat16)0.128379167f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.963902533f, -(BFloat16)0.414213562f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.983838529f, -(BFloat16)0.442695041f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.975367972f, -(BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.813763848f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.773942685f, (BFloat16)0.281718172f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.430301217f, -(BFloat16)0.141592654f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.9102f, (BFloat16)0.3633f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.8203f, (BFloat16)0.3066f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.7969f, (BFloat16)0.293f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.625f, (BFloat16)0.2148f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.3926f, -(BFloat16)0.1279f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.9648f, -(BFloat16)0.416f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.9844f, -(BFloat16)0.4434f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.9766f, -(BFloat16)0.4316f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.8125f, (BFloat16)0.3027f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.7734f, (BFloat16)0.2812f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.4297f, -(BFloat16)0.1416f, CrossPlatformMachineEpsilon }; } [Theory] @@ -1844,21 +1843,21 @@ public static IEnumerable Atan2Pi_TestData() yield return new object[] { BFloat16.Zero, -BFloat16.Zero, BFloat16.One, BFloat16.Zero }; // y: sinpi(0) x: -cospi(0.5) yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; // y: sinpi(0) x: cospi(0.5) yield return new object[] { BFloat16.Zero, BFloat16.One, BFloat16.Zero, BFloat16.Zero }; // y: sinpi(0) x: cospi(0) - yield return new object[] { (BFloat16)0.841470985f, (BFloat16)0.540302306f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; // y: sinpi(1 / pi) x: cospi(1 / pi) - yield return new object[] { (BFloat16)0.978770938f, (BFloat16)0.204957194f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; // y: sinpi(log10(e)) x: cospi(log10(e)) + yield return new object[] { (BFloat16)0.8398f, (BFloat16)0.5391f, (BFloat16)0.3184f, CrossPlatformMachineEpsilon }; // y: sinpi(1 / pi) x: cospi(1 / pi) + yield return new object[] { (BFloat16)0.9805f, (BFloat16)0.2051f, (BFloat16)0.4336f, CrossPlatformMachineEpsilon }; // y: sinpi(log10(e)) x: cospi(log10(e)) yield return new object[] { BFloat16.One, -BFloat16.Zero, (BFloat16)0.5f, BFloat16.Zero }; // y: sinpi(0.5) x: -cospi(0.5) yield return new object[] { BFloat16.One, BFloat16.Zero, (BFloat16)0.5f, BFloat16.Zero }; // y: sinpi(0.5) x: cospi(0.5) - yield return new object[] { (BFloat16)0.909297427f, -(BFloat16)0.416146837f, (BFloat16)0.636619772f, CrossPlatformMachineEpsilon }; // y: sinpi(2 / pi) x: cospi(2 / pi) - yield return new object[] { (BFloat16)0.821482831f, -(BFloat16)0.570233249f, (BFloat16)0.693147181f, CrossPlatformMachineEpsilon }; // y: sinpi(ln(2)) x: cospi(ln(2)) - yield return new object[] { (BFloat16)0.795693202f, -(BFloat16)0.605699867f, (BFloat16)0.707106781f, CrossPlatformMachineEpsilon }; // y: sinpi(1 / sqrt(2)) x: cospi(1 / sqrt(2)) - yield return new object[] { (BFloat16)0.624265953f, -(BFloat16)0.781211892f, (BFloat16)0.785398163f, CrossPlatformMachineEpsilon }; // y: sinpi(pi / 4) x: cospi(pi / 4) - yield return new object[] { -(BFloat16)0.392469559f, -(BFloat16)0.919764995f, -(BFloat16)0.871620833f, CrossPlatformMachineEpsilon }; // y: sinpi(2 / sqrt(pi)) x: cospi(2 / sqrt(pi)) - yield return new object[] { -(BFloat16)0.963902533f, -(BFloat16)0.266255342f, -(BFloat16)0.585786438f, CrossPlatformMachineEpsilon }; // y: sinpi(sqrt(2)) x: cospi(sqrt(2)) - yield return new object[] { -(BFloat16)0.983838529f, -(BFloat16)0.179057946f, -(BFloat16)0.557304959f, CrossPlatformMachineEpsilon }; // y: sinpi(log2(e)) x: cospi(log2(e)) - yield return new object[] { -(BFloat16)0.975367972f, (BFloat16)0.220584041f, -(BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; // y: sinpi(pi / 2) x: cospi(pi / 2) - yield return new object[] { (BFloat16)0.813763848f, (BFloat16)0.581195664f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; // y: sinpi(ln(10)) x: cospi(ln(10)) - yield return new object[] { (BFloat16)0.773942685f, -(BFloat16)0.633255651f, (BFloat16)0.718281828f, CrossPlatformMachineEpsilon }; // y: sinpi(e) x: cospi(e) - yield return new object[] { -(BFloat16)0.430301217f, -(BFloat16)0.902685362f, -(BFloat16)0.858407346f, CrossPlatformMachineEpsilon }; // y: sinpi(pi) x: cospi(pi) + yield return new object[] { (BFloat16)0.9102f, -(BFloat16)0.416f, (BFloat16)0.6367f, CrossPlatformMachineEpsilon }; // y: sinpi(2 / pi) x: cospi(2 / pi) + yield return new object[] { (BFloat16)0.8203f, -(BFloat16)0.5703f, (BFloat16)0.6953f, CrossPlatformMachineEpsilon }; // y: sinpi(ln(2)) x: cospi(ln(2)) + yield return new object[] { (BFloat16)0.7969f, -(BFloat16)0.6055f, (BFloat16)0.707f, CrossPlatformMachineEpsilon }; // y: sinpi(1 / sqrt(2)) x: cospi(1 / sqrt(2)) + yield return new object[] { (BFloat16)0.625f, -(BFloat16)0.7812f, (BFloat16)0.7852f, CrossPlatformMachineEpsilon }; // y: sinpi(pi / 4) x: cospi(pi / 4) + yield return new object[] { -(BFloat16)0.3926f, -(BFloat16)0.918f, -(BFloat16)0.8711f, CrossPlatformMachineEpsilon }; // y: sinpi(2 / sqrt(pi)) x: cospi(2 / sqrt(pi)) + yield return new object[] { -(BFloat16)0.9648f, -(BFloat16)0.2656f, -(BFloat16)0.5859f, CrossPlatformMachineEpsilon }; // y: sinpi(sqrt(2)) x: cospi(sqrt(2)) + yield return new object[] { -(BFloat16)0.9844f, -(BFloat16)0.1787f, -(BFloat16)0.5586f, CrossPlatformMachineEpsilon }; // y: sinpi(log2(e)) x: cospi(log2(e)) + yield return new object[] { -(BFloat16)0.9766f, (BFloat16)0.2207f, -(BFloat16)0.4297f, CrossPlatformMachineEpsilon }; // y: sinpi(pi / 2) x: cospi(pi / 2) + yield return new object[] { (BFloat16)0.8125f, (BFloat16)0.582f, (BFloat16)0.3027f, CrossPlatformMachineEpsilon }; // y: sinpi(ln(10)) x: cospi(ln(10)) + yield return new object[] { (BFloat16)0.7734f, -(BFloat16)0.6328f, (BFloat16)0.7188f, CrossPlatformMachineEpsilon }; // y: sinpi(e) x: cospi(e) + yield return new object[] { -(BFloat16)0.4297f, -(BFloat16)0.9023f, -(BFloat16)0.8594f, CrossPlatformMachineEpsilon }; // y: sinpi(pi) x: cospi(pi) yield return new object[] { BFloat16.One, BFloat16.NegativeInfinity, BFloat16.One, BFloat16.Zero }; // y: sinpi(0.5) yield return new object[] { BFloat16.One, BFloat16.PositiveInfinity, BFloat16.Zero, BFloat16.Zero }; // y: sinpi(0.5) yield return new object[] { BFloat16.PositiveInfinity, -BFloat16.One, (BFloat16)0.5f, BFloat16.Zero }; // x: cospi(1) @@ -1879,20 +1878,20 @@ public static IEnumerable AtanPi_TestData() { yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.55740773f, (BFloat16)0.318309886f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)4.77548954f, (BFloat16)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)1.555f, (BFloat16)0.3184f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)4.781f, (BFloat16)0.4336f, CrossPlatformMachineEpsilon }; yield return new object[] { BFloat16.PositiveInfinity, (BFloat16)0.5f, BFloat16.Zero }; - yield return new object[] { -(BFloat16)2.18503986f, -(BFloat16)0.363380228f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)1.44060844f, -(BFloat16)0.306852819f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)1.31367571f, -(BFloat16)0.292893219f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)0.79909940f, -(BFloat16)0.214601837f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.42670634f, (BFloat16)0.128379167f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)3.62021857f, (BFloat16)0.414213562f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)5.49452594f, (BFloat16)0.442695041f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)4.42175222f, -(BFloat16)0.429203673f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)1.40015471f, (BFloat16)0.302585093f, CrossPlatformMachineEpsilon }; - yield return new object[] { -(BFloat16)1.22216467f, -(BFloat16)0.281718172f, CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)0.476690146f, (BFloat16)0.141592654f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)2.188f, -(BFloat16)0.3633f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.438f, -(BFloat16)0.3066f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.312f, -(BFloat16)0.293f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)0.8008f, -(BFloat16)0.2148f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.4258f, (BFloat16)0.1279f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)3.625f, (BFloat16)0.4141f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)5.5f, (BFloat16)0.4434f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)4.406f, -(BFloat16)0.4297f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)1.398f, (BFloat16)0.3027f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(BFloat16)1.219f, -(BFloat16)0.2812f, CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)0.4766f, (BFloat16)0.1416f, CrossPlatformMachineEpsilon }; } [Theory] @@ -1907,25 +1906,25 @@ public static IEnumerable CosPi_TestData() { yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.One, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.318309886f, (BFloat16)0.540302306f, CrossPlatformMachineEpsilon }; // value: (1 / pi) - yield return new object[] { (BFloat16)0.434294482f, (BFloat16)0.204957194f, CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)0.3184f, (BFloat16)0.5391f, CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)0.4336f, (BFloat16)0.207f, CrossPlatformMachineEpsilon }; // value: (log10(e)) yield return new object[] { (BFloat16)0.5f, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.636619772f, -(BFloat16)0.416146837f, CrossPlatformMachineEpsilon }; // value: (2 / pi) - yield return new object[] { (BFloat16)0.693147181f, -(BFloat16)0.570233249f, CrossPlatformMachineEpsilon }; // value: (ln(2)) - yield return new object[] { (BFloat16)0.707106781f, -(BFloat16)0.605699867f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)0.785398163f, -(BFloat16)0.781211892f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)0.6367f, -(BFloat16)0.416f, CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)0.6914f, -(BFloat16)0.5664f, CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)0.707f, -(BFloat16)0.6055f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)0.7852f, -(BFloat16)0.7812f, CrossPlatformMachineEpsilon }; // value: (pi / 4) yield return new object[] { BFloat16.One, -(BFloat16)1.0f, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.12837917f, -(BFloat16)0.919764995f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)1.41421356f, -(BFloat16)0.266255342f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)1.44269504f, -(BFloat16)0.179057946f, CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)1.125f, -(BFloat16)0.9258f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)1.414f, -(BFloat16)0.2676f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)1.445f, -(BFloat16)0.1709f, CrossPlatformMachineEpsilon }; // value: (log2(e)) yield return new object[] { (BFloat16)1.5f, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.57079633f, (BFloat16)0.220584041f, CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)1.57f, (BFloat16)0.2188f, CrossPlatformMachineEpsilon }; // value: (pi / 2) yield return new object[] { (BFloat16)2.0f, (BFloat16)1.0, BFloat16.Zero }; - yield return new object[] { (BFloat16)2.30258509f, (BFloat16)0.581195664f, CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)2.297f, (BFloat16)0.5938f, CrossPlatformMachineEpsilon }; // value: (ln(10)) yield return new object[] { (BFloat16)2.5f, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)2.71828183f, -(BFloat16)0.633255651f, CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)2.719f, -(BFloat16)0.6328f, CrossPlatformMachineEpsilon }; // value: (e) yield return new object[] { (BFloat16)3.0f, -(BFloat16)1.0, BFloat16.Zero }; - yield return new object[] { (BFloat16)3.14159265f, -(BFloat16)0.902685362f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)3.141f, -(BFloat16)0.9023f, CrossPlatformMachineEpsilon }; // value: (pi) yield return new object[] { (BFloat16)3.5f, BFloat16.Zero, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.Zero }; } @@ -1942,26 +1941,26 @@ public static IEnumerable SinPi_TestData() { yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.318309886f, (BFloat16)0.841470985f, CrossPlatformMachineEpsilon }; // value: (1 / pi) - yield return new object[] { (BFloat16)0.434294482f, (BFloat16)0.978770938f, CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)0.3184f, (BFloat16)0.8398f, CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (BFloat16)0.4336f, (BFloat16)0.9766f, CrossPlatformMachineEpsilon }; // value: (log10(e)) yield return new object[] { (BFloat16)0.5f, BFloat16.One, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.636619772f, (BFloat16)0.909297427f, CrossPlatformMachineEpsilon }; // value: (2 / pi) - yield return new object[] { (BFloat16)0.693147181f, (BFloat16)0.821482831f, CrossPlatformMachineEpsilon }; // value: (ln(2)) - yield return new object[] { (BFloat16)0.707106781f, (BFloat16)0.795693202f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)0.785398163f, (BFloat16)0.624265953f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)0.6367f, (BFloat16)0.9102f, CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (BFloat16)0.6914f, (BFloat16)0.8242f, CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)0.707f, (BFloat16)0.7969f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)0.7852f, (BFloat16)0.625f, CrossPlatformMachineEpsilon }; // value: (pi / 4) yield return new object[] { BFloat16.One, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.12837917f, -(BFloat16)0.392469559f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)1.41421356f, -(BFloat16)0.963902533f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)1.44269504f, -(BFloat16)0.983838529f, CrossPlatformMachineEpsilon }; // value: (log2(e)) - yield return new object[] { (BFloat16)1.5f, -(BFloat16)1.0f, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.57079633f, -(BFloat16)0.975367972f, CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)1.125f, -(BFloat16)0.3828f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)1.414f, -(BFloat16)0.9648f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)1.445f, -(BFloat16)0.9844f, CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)1.5f, -(BFloat16)1f, BFloat16.Zero }; + yield return new object[] { (BFloat16)1.57f, -(BFloat16)0.9766f, CrossPlatformMachineEpsilon }; // value: (pi / 2) yield return new object[] { (BFloat16)2.0f, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)2.30258509f, (BFloat16)0.813763848f, CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)2.297f, (BFloat16)0.8047f, CrossPlatformMachineEpsilon }; // value: (ln(10)) yield return new object[] { (BFloat16)2.5f, BFloat16.One, BFloat16.Zero }; - yield return new object[] { (BFloat16)2.71828183f, (BFloat16)0.773942685f, CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)2.719f, (BFloat16)0.7734f, CrossPlatformMachineEpsilon }; // value: (e) yield return new object[] { (BFloat16)3.0f, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)3.14159265f, -(BFloat16)0.430301217f, CrossPlatformMachineEpsilon }; // value: (pi) - yield return new object[] { (BFloat16)3.5f, -(BFloat16)1.0f, BFloat16.Zero }; + yield return new object[] { (BFloat16)3.141f, -(BFloat16)0.4277f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)3.5f, -(BFloat16)1f, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.Zero }; } @@ -1977,25 +1976,25 @@ public static IEnumerable TanPi_TestData() { yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.318309886f, (BFloat16)1.55740772f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) - yield return new object[] { (BFloat16)0.434294482f, (BFloat16)4.77548954f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) + yield return new object[] { (BFloat16)0.3184f, (BFloat16)1.555f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / pi) + yield return new object[] { (BFloat16)0.4336f, (BFloat16)4.719f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log10(e)) yield return new object[] { (BFloat16)0.5f, BFloat16.PositiveInfinity, BFloat16.Zero }; - yield return new object[] { (BFloat16)0.636619772f, -(BFloat16)2.18503986f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) - yield return new object[] { (BFloat16)0.693147181f, -(BFloat16)1.44060844f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) - yield return new object[] { (BFloat16)0.707106781f, -(BFloat16)1.31367571f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)0.785398163f, -(BFloat16)0.799099398f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)0.6367f, -(BFloat16)2.188f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (2 / pi) + yield return new object[] { (BFloat16)0.6914f, -(BFloat16)1.461f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(2)) + yield return new object[] { (BFloat16)0.707f, -(BFloat16)1.312f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)0.7852f, -(BFloat16)0.8008f, CrossPlatformMachineEpsilon }; // value: (pi / 4) yield return new object[] { BFloat16.One, -BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.12837917f, (BFloat16)0.426706344f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)1.41421356f, (BFloat16)3.62021857f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)1.44269504f, (BFloat16)5.49452594f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) + yield return new object[] { (BFloat16)1.125f, (BFloat16)0.4141f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)1.414f, (BFloat16)3.609f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)1.445f, (BFloat16)5.75f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (log2(e)) yield return new object[] { (BFloat16)1.5f, BFloat16.NegativeInfinity, BFloat16.Zero }; - yield return new object[] { (BFloat16)1.57079633f, -(BFloat16)4.42175222f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) + yield return new object[] { (BFloat16)1.57f, -(BFloat16)4.469f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (pi / 2) yield return new object[] { (BFloat16)2.0f, BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)2.30258509f, (BFloat16)1.40015471f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) + yield return new object[] { (BFloat16)2.297f, (BFloat16)1.352f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (ln(10)) yield return new object[] { (BFloat16)2.5f, BFloat16.PositiveInfinity, BFloat16.Zero }; - yield return new object[] { (BFloat16)2.71828183f, -(BFloat16)1.22216467f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) + yield return new object[] { (BFloat16)2.719f, -(BFloat16)1.219f, CrossPlatformMachineEpsilon * (BFloat16)10 }; // value: (e) yield return new object[] { (BFloat16)3.0f, -BFloat16.Zero, BFloat16.Zero }; - yield return new object[] { (BFloat16)3.14159265f, (BFloat16)0.476690146f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)3.141f, (BFloat16)0.4727f, CrossPlatformMachineEpsilon }; // value: (pi) yield return new object[] { (BFloat16)3.5f, BFloat16.NegativeInfinity, BFloat16.Zero }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.NaN, BFloat16.Zero }; } @@ -2144,25 +2143,25 @@ public static IEnumerable DegreesToRadians_TestData() yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; yield return new object[] { (BFloat16)(0.3184f), (BFloat16)(0.005554f), CrossPlatformMachineEpsilon }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.4343f), (BFloat16)(0.00758f), CrossPlatformMachineEpsilon }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.5f), (BFloat16)(0.00872f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.4336f), (BFloat16)(0.007568f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.5f), (BFloat16)(0.008728f), CrossPlatformMachineEpsilon }; yield return new object[] { (BFloat16)(0.6367f), (BFloat16)(0.01111f), CrossPlatformMachineEpsilon }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.6934f), (BFloat16)(0.0121f), CrossPlatformMachineEpsilon }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.707f), (BFloat16)(0.01234f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.785f), (BFloat16)(0.0137f), CrossPlatformMachineEpsilon }; // value: (pi / 4) - yield return new object[] { (BFloat16)(1.0f), (BFloat16)(0.01744f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(1.128f), (BFloat16)(0.01968f), CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(1.414f), (BFloat16)(0.02467f), CrossPlatformMachineEpsilon }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(1.442f), (BFloat16)(0.02518f), CrossPlatformMachineEpsilon }; // value: (log2(e)) - yield return new object[] { (BFloat16)(1.5f), (BFloat16)(0.02617f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(1.57f), (BFloat16)(0.0274f), CrossPlatformMachineEpsilon }; // value: (pi / 2) - yield return new object[] { (BFloat16)(2.0f), (BFloat16)(0.03488f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(2.303f), (BFloat16)(0.04016f), CrossPlatformMachineEpsilon }; // value: (ln(10)) - yield return new object[] { (BFloat16)(2.5f), (BFloat16)(0.0436f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(2.719f), (BFloat16)(0.04742f), CrossPlatformMachineEpsilon }; // value: (e) - yield return new object[] { (BFloat16)(3.0f), (BFloat16)(0.05234f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(3.14f), (BFloat16)(0.0548f), CrossPlatformMachineEpsilon }; // value: (pi) - yield return new object[] { (BFloat16)(3.5f), (BFloat16)(0.06107f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.6953f), (BFloat16)(0.01215f), CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.707f), (BFloat16)(0.01233f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.7852f), (BFloat16)(0.01373f), CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)(1.0f), (BFloat16)(0.01746f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(1.125f), (BFloat16)(0.01965f), CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(1.414f), (BFloat16)(0.02466f), CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(1.445f), (BFloat16)(0.02527f), CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)(1.5f), (BFloat16)(0.02612f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(1.57f), (BFloat16)(0.02747f), CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)(2.0f), (BFloat16)(0.03491f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(2.297f), (BFloat16)(0.04004f), CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)(2.5f), (BFloat16)(0.0437f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(2.719f), (BFloat16)(0.04736f), CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)(3.0f), (BFloat16)(0.05225f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(3.141f), (BFloat16)(0.05493f), CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)(3.5f), (BFloat16)(0.06104f), CrossPlatformMachineEpsilon }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, BFloat16.Zero }; } @@ -2179,25 +2178,25 @@ public static IEnumerable RadiansToDegrees_TestData() yield return new object[] { BFloat16.NaN, BFloat16.NaN, BFloat16.Zero }; yield return new object[] { BFloat16.Zero, BFloat16.Zero, BFloat16.Zero }; yield return new object[] { (BFloat16)(0.005554f), (BFloat16)(0.3184f), CrossPlatformMachineEpsilon }; // value: (1 / pi) - yield return new object[] { (BFloat16)(0.00758f), (BFloat16)(0.4343f), CrossPlatformMachineEpsilon }; // value: (log10(e)) - yield return new object[] { (BFloat16)(0.00872f), (BFloat16)(0.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.007568f), (BFloat16)(0.4336f), CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (BFloat16)(0.008728f), (BFloat16)(0.5f), CrossPlatformMachineEpsilon }; yield return new object[] { (BFloat16)(0.01111f), (BFloat16)(0.6367f), CrossPlatformMachineEpsilon }; // value: (2 / pi) - yield return new object[] { (BFloat16)(0.0121f), (BFloat16)(0.6934f), CrossPlatformMachineEpsilon }; // value: (ln(2)) - yield return new object[] { (BFloat16)(0.01234f), (BFloat16)(0.707f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) - yield return new object[] { (BFloat16)(0.0137f), (BFloat16)(0.785f), CrossPlatformMachineEpsilon }; // value: (pi / 4) - yield return new object[] { (BFloat16)(0.01744f), (BFloat16)(1.0f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(0.01968f), (BFloat16)(1.128f), CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) - yield return new object[] { (BFloat16)(0.02467f), (BFloat16)(1.414f), CrossPlatformMachineEpsilon }; // value: (sqrt(2)) - yield return new object[] { (BFloat16)(0.02518f), (BFloat16)(1.442f), CrossPlatformMachineEpsilon }; // value: (log2(e)) - yield return new object[] { (BFloat16)(0.02617f), (BFloat16)(1.5f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(0.0274f), (BFloat16)(1.57f), CrossPlatformMachineEpsilon }; // value: (pi / 2) - yield return new object[] { (BFloat16)(0.03488f), (BFloat16)(2.0f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(0.04016f), (BFloat16)(2.303f), CrossPlatformMachineEpsilon }; // value: (ln(10)) - yield return new object[] { (BFloat16)(0.0436f), (BFloat16)(2.5f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(0.04742f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon }; // value: (e) - yield return new object[] { (BFloat16)(0.05234f), (BFloat16)(3.0f), CrossPlatformMachineEpsilon }; - yield return new object[] { (BFloat16)(0.0548f), (BFloat16)(3.14f), CrossPlatformMachineEpsilon }; // value: (pi) - yield return new object[] { (BFloat16)(0.06107f), (BFloat16)(3.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.01208f), (BFloat16)(0.6914f), CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (BFloat16)(0.01233f), (BFloat16)(0.707f), CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (BFloat16)(0.01367f), (BFloat16)(0.7852f), CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { (BFloat16)(0.01746f), (BFloat16)(1f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.01965f), (BFloat16)(1.125f), CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (BFloat16)(0.02466f), (BFloat16)(1.414f), CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (BFloat16)(0.02515f), (BFloat16)(1.438f), CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (BFloat16)(0.02612f), (BFloat16)(1.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.02734f), (BFloat16)(1.57f), CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (BFloat16)(0.03491f), (BFloat16)(2f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.04004f), (BFloat16)(2.297f), CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (BFloat16)(0.0437f), (BFloat16)(2.5f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.04736f), (BFloat16)(2.719f), CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (BFloat16)(0.05225f), (BFloat16)(3f), CrossPlatformMachineEpsilon }; + yield return new object[] { (BFloat16)(0.05469f), (BFloat16)(3.141f), CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (BFloat16)(0.06104f), (BFloat16)(3.5f), CrossPlatformMachineEpsilon }; yield return new object[] { BFloat16.PositiveInfinity, BFloat16.PositiveInfinity, BFloat16.Zero }; } From 9938e8beb8a1d0008f4cd74ff4b5c0c0bd6386d3 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 30 Dec 2024 00:38:03 +0800 Subject: [PATCH 53/67] Align with TryWriteBig/LittleEndian --- .../src/System/Numerics/BFloat16.cs | 66 +++++-------------- 1 file changed, 18 insertions(+), 48 deletions(-) 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 2b4b7045281214..04f5412fcbc526 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -961,17 +961,13 @@ bool IFloatingPoint.TryWriteExponentBigEndian(Span destination, { if (destination.Length >= sizeof(sbyte)) { - sbyte exponent = Exponent; - Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), exponent); - + destination[0] = (byte)Exponent; bytesWritten = sizeof(sbyte); return true; } - else - { - bytesWritten = 0; - return false; - } + + bytesWritten = 0; + return false; } /// @@ -979,65 +975,39 @@ bool IFloatingPoint.TryWriteExponentLittleEndian(Span destinatio { if (destination.Length >= sizeof(sbyte)) { - sbyte exponent = Exponent; - Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), exponent); - + destination[0] = (byte)Exponent; bytesWritten = sizeof(sbyte); return true; } - else - { - bytesWritten = 0; - return false; - } + + bytesWritten = 0; + return false; } /// bool IFloatingPoint.TryWriteSignificandBigEndian(Span destination, out int bytesWritten) { - if (destination.Length >= sizeof(ushort)) + if (BinaryPrimitives.TryWriteUInt16BigEndian(destination, Significand)) { - ushort significand = Significand; - - if (BitConverter.IsLittleEndian) - { - significand = BinaryPrimitives.ReverseEndianness(significand); - } - - Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), significand); - - bytesWritten = sizeof(ushort); + bytesWritten = sizeof(uint); return true; } - else - { - bytesWritten = 0; - return false; - } + + bytesWritten = 0; + return false; } /// bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destination, out int bytesWritten) { - if (destination.Length >= sizeof(ushort)) + if (BinaryPrimitives.TryWriteUInt16LittleEndian(destination, Significand)) { - ushort significand = Significand; - - if (!BitConverter.IsLittleEndian) - { - significand = BinaryPrimitives.ReverseEndianness(significand); - } - - Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), significand); - - bytesWritten = sizeof(ushort); + bytesWritten = sizeof(uint); return true; } - else - { - bytesWritten = 0; - return false; - } + + bytesWritten = 0; + return false; } // From b889417de4bd1dbcffc1ecd8c906d71b2d4fbf1b Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 31 Dec 2024 13:51:16 +0800 Subject: [PATCH 54/67] Remove redundant 'partial' --- .../System.Private.CoreLib/src/System/Number.Grisu3.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs index 74e9b62b07d278..e4a25b9b5939c6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs @@ -16,7 +16,7 @@ internal static partial class Number // The general idea behind Grisu3 is to leverage additional bits and cached powers of ten to generate the correct digits. // The algorithm is imprecise for some numbers. Fortunately, the algorithm itself can determine this scenario and gives us // a result indicating success or failure. We must fallback to a different algorithm for the failing scenario. - internal static partial class Grisu3 + internal static class Grisu3 { private const int CachedPowersDecimalExponentDistance = 8; private const int CachedPowersMinDecimalExponent = -348; From 922f4114901d3f35f0a1082ae413ea6b196770c5 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 6 Feb 2025 18:09:02 +0800 Subject: [PATCH 55/67] Use DefaultParseStyle --- .../src/System/Numerics/BFloat16.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 04f5412fcbc526..d52f332e0bd14c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -230,7 +230,7 @@ public static bool IsZero(BFloat16 value) /// /// The input to be parsed. /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. - public static BFloat16 Parse(string s) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null); + public static BFloat16 Parse(string s) => Parse(s, DefaultParseStyle, provider: null); /// /// Parses a from a in the given . @@ -246,7 +246,7 @@ public static bool IsZero(BFloat16 value) /// The input to be parsed. /// A format provider. /// The equivalent value representing the input string. If the input exceeds BFloat16's range, a or is returned. - public static BFloat16 Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider); + public static BFloat16 Parse(string s, IFormatProvider? provider) => Parse(s, DefaultParseStyle, provider); /// /// Parses a from a with the given and . @@ -283,7 +283,7 @@ public static BFloat16 Parse(ReadOnlySpan s, NumberStyles style = DefaultP /// The input to be parsed. /// The equivalent value representing the input string if the parse was successful. If the input exceeds BFloat16's range, a or is returned. If the parse was unsuccessful, a default value is returned. /// if the parse was successful, otherwise. - public static bool TryParse([NotNullWhen(true)] string? s, out BFloat16 result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); + public static bool TryParse([NotNullWhen(true)] string? s, out BFloat16 result) => TryParse(s, DefaultParseStyle, provider: null, out result); /// /// Tries to parse a from a in the default parse style. @@ -291,13 +291,13 @@ public static BFloat16 Parse(ReadOnlySpan s, NumberStyles style = DefaultP /// The input to be parsed. /// The equivalent value representing the input string if the parse was successful. If the input exceeds BFloat16's range, a or is returned. If the parse was unsuccessful, a default value is returned. /// if the parse was successful, otherwise. - public static bool TryParse(ReadOnlySpan s, out BFloat16 result) => TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); + public static bool TryParse(ReadOnlySpan s, out BFloat16 result) => TryParse(s, DefaultParseStyle, provider: null, out result); /// Tries to convert a UTF-8 character span containing the string representation of a number to its number equivalent. /// A read-only UTF-8 character span that contains the number to convert. /// When this method returns, contains a number equivalent of the numeric value or symbol contained in if the conversion succeeded or zero if the conversion failed. The conversion fails if the is or is not in a valid format. This parameter is passed uninitialized; any value originally supplied in result will be overwritten. /// true if was converted successfully; otherwise, false. - public static bool TryParse(ReadOnlySpan utf8Text, out BFloat16 result) => TryParse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider: null, out result); + public static bool TryParse(ReadOnlySpan utf8Text, out BFloat16 result) => TryParse(utf8Text, DefaultParseStyle, provider: null, out result); /// /// Tries to parse a from a with the given and . @@ -1945,7 +1945,7 @@ public static (BFloat16 SinPi, BFloat16 CosPi) SinCosPi(BFloat16 x) // /// - public static BFloat16 Parse(ReadOnlySpan utf8Text, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null) + public static BFloat16 Parse(ReadOnlySpan utf8Text, NumberStyles style = DefaultParseStyle, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.ParseFloat(utf8Text, style, NumberFormatInfo.GetInstance(provider)); @@ -1959,10 +1959,10 @@ public static bool TryParse(ReadOnlySpan utf8Text, NumberStyles style, IFo } /// - public static BFloat16 Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) => Parse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider); + public static BFloat16 Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) => Parse(utf8Text, DefaultParseStyle, provider); /// - public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, out BFloat16 result) => TryParse(utf8Text, NumberStyles.Float | NumberStyles.AllowThousands, provider, out result); + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, out BFloat16 result) => TryParse(utf8Text, DefaultParseStyle, provider, out result); // // IBinaryFloatParseAndFormatInfo From 86dce2d4fb1c2ebf1b152d042296f554c4a9253c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 7 Feb 2025 01:58:30 +0800 Subject: [PATCH 56/67] Fill conversion in signed integer --- .../src/System/Int128.cs | 20 +++++++++++++++++++ .../src/System/Int16.cs | 20 +++++++++++++++++++ .../src/System/Int32.cs | 20 +++++++++++++++++++ .../src/System/Int64.cs | 20 +++++++++++++++++++ .../src/System/IntPtr.cs | 20 +++++++++++++++++++ .../src/System/Numerics/BFloat16.cs | 2 ++ .../src/System/SByte.cs | 20 +++++++++++++++++++ 7 files changed, 122 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index a2a4d792115346..56331fadf8c32c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -1521,6 +1521,12 @@ private static bool TryConvertFromChecked(TOther value, out Int128 resul result = checked((Int128)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((Int128)actualValue); + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1595,6 +1601,13 @@ private static bool TryConvertFromSaturating(TOther value, out Int128 re (actualValue == Half.NegativeInfinity) ? MinValue : (Int128)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x7F00)) ? MaxValue : + (actualValue <= new BFloat16(0xFF00)) ? MinValue : (Int128)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1670,6 +1683,13 @@ private static bool TryConvertFromTruncating(TOther value, out Int128 re (actualValue == Half.NegativeInfinity) ? MinValue : (Int128)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x7F00)) ? MaxValue : + (actualValue <= new BFloat16(0xFF00)) ? MinValue : (Int128)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index b1a90999ea5e9e..de9296d1f66db6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -898,6 +898,12 @@ private static bool TryConvertFromChecked(TOther value, out short result result = checked((short)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((short)actualValue); + return true; + } else if (typeof(TOther) == typeof(int)) { int actualValue = (int)(object)value; @@ -972,6 +978,13 @@ private static bool TryConvertFromSaturating(TOther value, out short res (actualValue <= BitConverter.UInt16BitsToHalf(0xF800)) ? MinValue : (short)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x4700)) ? MaxValue : + (actualValue <= new BFloat16(0xB700)) ? MinValue : (short)actualValue; + return true; + } else if (typeof(TOther) == typeof(int)) { int actualValue = (int)(object)value; @@ -1051,6 +1064,13 @@ private static bool TryConvertFromTruncating(TOther value, out short res (actualValue <= BitConverter.UInt16BitsToHalf(0xF800)) ? MinValue : (short)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x4700)) ? MaxValue : + (actualValue <= new BFloat16(0xB700)) ? MinValue : (short)actualValue; + return true; + } else if (typeof(TOther) == typeof(int)) { int actualValue = (int)(object)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index 9a3a2d76a260da..548faf6a182464 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -939,6 +939,12 @@ private static bool TryConvertFromChecked(TOther value, out int result) result = checked((int)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((int)actualValue); + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1013,6 +1019,13 @@ private static bool TryConvertFromSaturating(TOther value, out int resul (actualValue == Half.NegativeInfinity) ? MinValue : (int)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x4F00)) ? MaxValue : + (actualValue <= new BFloat16(0xBF00)) ? MinValue : (int)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1091,6 +1104,13 @@ private static bool TryConvertFromTruncating(TOther value, out int resul (actualValue == Half.NegativeInfinity) ? MinValue : (int)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x4F00)) ? MaxValue : + (actualValue <= new BFloat16(0xBF00)) ? MinValue : (int)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index c0417fdbe93fe3..53fe0eeb0d2156 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -936,6 +936,12 @@ private static bool TryConvertFromChecked(TOther value, out long result) result = checked((long)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((long)actualValue); + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1010,6 +1016,13 @@ private static bool TryConvertFromSaturating(TOther value, out long resu (actualValue == Half.NegativeInfinity) ? MinValue : (long)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x5F00)) ? MaxValue : + (actualValue <= new BFloat16(0xCF00)) ? MinValue : (long)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1086,6 +1099,13 @@ private static bool TryConvertFromTruncating(TOther value, out long resu (actualValue == Half.NegativeInfinity) ? MinValue : (long)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= new BFloat16(0x5F00)) ? MaxValue : + (actualValue <= new BFloat16(0xCF00)) ? MinValue : (long)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs index 0145ae19695c8f..2be890106ab50e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs @@ -931,6 +931,12 @@ private static bool TryConvertFromChecked(TOther value, out nint result) result = checked((nint)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((nint)actualValue); + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1005,6 +1011,13 @@ private static bool TryConvertFromSaturating(TOther value, out nint resu (actualValue == Half.NegativeInfinity) ? unchecked((nint)nint_t.MinValue) : (nint)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= (BFloat16)nint_t.MaxValue) ? unchecked((nint)nint_t.MaxValue) : + (actualValue <= (BFloat16)nint_t.MinValue) ? unchecked((nint)nint_t.MinValue) : (nint)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1082,6 +1095,13 @@ private static bool TryConvertFromTruncating(TOther value, out nint resu (actualValue == Half.NegativeInfinity) ? unchecked((nint)nint_t.MinValue) : (nint)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= (BFloat16)nint_t.MaxValue) ? unchecked((nint)nint_t.MaxValue) : + (actualValue <= (BFloat16)nint_t.MinValue) ? unchecked((nint)nint_t.MinValue) : (nint)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; 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 d52f332e0bd14c..ad8df5bf9b9f7c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -1503,6 +1503,7 @@ static bool INumberBase.TryConvertFromTruncating(TOther value, return TryConvertFrom(value, out result); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertFrom(TOther value, out BFloat16 result) where TOther : INumberBase { @@ -1688,6 +1689,7 @@ static bool INumberBase.TryConvertToTruncating(BFloat16 value, return TryConvertTo(value, out result); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase { diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index 4ba9c4372de61b..5876426392be92 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -861,6 +861,12 @@ private static bool TryConvertFromChecked(TOther value, out sbyte result result = checked((sbyte)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((sbyte)actualValue); + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -935,6 +941,13 @@ private static bool TryConvertFromSaturating(TOther value, out sbyte res (actualValue <= MinValue) ? MinValue : (sbyte)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= MaxValue) ? MaxValue : + (actualValue <= MinValue) ? MinValue : (sbyte)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1015,6 +1028,13 @@ private static bool TryConvertFromTruncating(TOther value, out sbyte res (actualValue <= MinValue) ? MinValue : (sbyte)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (actualValue >= MaxValue) ? MaxValue : + (actualValue <= MinValue) ? MinValue : (sbyte)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; From 9f729a3f58758ebe55bfe253d001c33dc6c2429d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 7 Feb 2025 02:03:47 +0800 Subject: [PATCH 57/67] Fill conversion in unsigned integer and floating point --- .../System.Private.CoreLib/src/System/Byte.cs | 18 ++++++++++++++++++ .../src/System/Double.cs | 6 ++++++ .../src/System/Single.cs | 6 ++++++ .../src/System/UInt128.cs | 18 ++++++++++++++++++ .../src/System/UInt16.cs | 18 ++++++++++++++++++ .../src/System/UInt32.cs | 18 ++++++++++++++++++ .../src/System/UInt64.cs | 18 ++++++++++++++++++ .../src/System/UIntPtr.cs | 18 ++++++++++++++++++ 8 files changed, 120 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index 1c933aaaced78b..dea7ed15ce1a64 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -906,6 +906,12 @@ static bool INumberBase.TryConvertToChecked(byte value, [MaybeNull result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = value; @@ -980,6 +986,12 @@ static bool INumberBase.TryConvertToSaturating(byte value, [MaybeN result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = value; @@ -1054,6 +1066,12 @@ static bool INumberBase.TryConvertToTruncating(byte value, [MaybeN result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index a5adb8057f6a5e..fc000b8df3ddf8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -1248,6 +1248,12 @@ private static bool TryConvertFrom(TOther value, out double result) result = (double)actualValue; return true; } + if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (double)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index a61d297123f22a..04b036c24561d6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -1273,6 +1273,12 @@ private static bool TryConvertFrom(TOther value, out float result) result = (float)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = (float)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs index b6b4e59bb5545d..8817ada4732202 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs @@ -1791,6 +1791,12 @@ static bool INumberBase.TryConvertToChecked(UInt128 value, [May result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -1865,6 +1871,12 @@ static bool INumberBase.TryConvertToSaturating(UInt128 value, [ result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= new UInt128(0x0000_0000_0000_0000, 0x0000_0000_0000_7FFF)) ? short.MaxValue : (short)value; @@ -1945,6 +1957,12 @@ static bool INumberBase.TryConvertToTruncating(UInt128 value, [ result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (short)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index 87d4f12a9a10d9..189e1a2f401e0b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -925,6 +925,12 @@ static bool INumberBase.TryConvertToChecked(ushort value, [Maybe result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -999,6 +1005,12 @@ static bool INumberBase.TryConvertToSaturating(ushort value, [Ma result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= short.MaxValue) ? short.MaxValue : (short)value; @@ -1073,6 +1085,12 @@ static bool INumberBase.TryConvertToTruncating(ushort value, [Ma result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (short)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs index a774069fb560b2..9830c845cbbf05 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs @@ -964,6 +964,12 @@ static bool INumberBase.TryConvertToChecked(uint value, [MaybeNull result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -1038,6 +1044,12 @@ static bool INumberBase.TryConvertToSaturating(uint value, [MaybeN result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= (uint)short.MaxValue) ? short.MaxValue : (short)value; @@ -1118,6 +1130,12 @@ static bool INumberBase.TryConvertToTruncating(uint value, [MaybeN result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (short)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index 56d9fc2cc2015a..52c68dd6ac8eae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -963,6 +963,12 @@ static bool INumberBase.TryConvertToChecked(ulong value, [MaybeNu result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -1037,6 +1043,12 @@ static bool INumberBase.TryConvertToSaturating(ulong value, [Mayb result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= (ulong)short.MaxValue) ? short.MaxValue : (short)value; @@ -1111,6 +1123,12 @@ static bool INumberBase.TryConvertToTruncating(ulong value, [Mayb result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (short)value; diff --git a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs index 7ab359b04199bc..73d7f2eb3cd061 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs @@ -966,6 +966,12 @@ static bool INumberBase.TryConvertToChecked(nuint value, [MaybeNu result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -1040,6 +1046,12 @@ static bool INumberBase.TryConvertToSaturating(nuint value, [Mayb result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= (nuint)short.MaxValue) ? short.MaxValue : (short)value; @@ -1114,6 +1126,12 @@ static bool INumberBase.TryConvertToTruncating(nuint value, [Mayb result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (short)value; From 6baf9406e7d3bb317c8285f2603348a57e7122bf Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 7 Feb 2025 02:28:56 +0800 Subject: [PATCH 58/67] Add conversion for S.R.Numerics --- .../ref/System.Runtime.Numerics.cs | 3 ++ .../src/System/Numerics/BigInteger.cs | 52 +++++++++++++++++++ .../src/System/Numerics/Complex.cs | 32 ++++++++++++ 3 files changed, 87 insertions(+) diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index 5ac9e6237bea3e..f08e7b7071d326 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -93,12 +93,14 @@ namespace System.Numerics public static explicit operator System.Numerics.BigInteger (decimal value) { throw null; } public static explicit operator System.Numerics.BigInteger (double value) { throw null; } public static explicit operator System.Numerics.BigInteger (System.Half value) { throw null; } + public static explicit operator System.Numerics.BigInteger (System.Numerics.BFloat16 value) { throw null; } public static explicit operator byte (System.Numerics.BigInteger value) { throw null; } public static explicit operator char (System.Numerics.BigInteger value) { throw null; } public static explicit operator decimal (System.Numerics.BigInteger value) { throw null; } public static explicit operator double (System.Numerics.BigInteger value) { throw null; } public static explicit operator System.Half (System.Numerics.BigInteger value) { throw null; } public static explicit operator System.Int128 (System.Numerics.BigInteger value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (System.Numerics.BigInteger value) { throw null; } public static explicit operator short (System.Numerics.BigInteger value) { throw null; } public static explicit operator int (System.Numerics.BigInteger value) { throw null; } public static explicit operator long (System.Numerics.BigInteger value) { throw null; } @@ -322,6 +324,7 @@ namespace System.Numerics public static implicit operator System.Numerics.Complex (char value) { throw null; } public static implicit operator System.Numerics.Complex (double value) { throw null; } public static implicit operator System.Numerics.Complex (System.Half value) { throw null; } + public static implicit operator System.Numerics.Complex (System.Numerics.BFloat16 value) { throw null; } public static implicit operator System.Numerics.Complex (short value) { throw null; } public static implicit operator System.Numerics.Complex (int value) { throw null; } public static implicit operator System.Numerics.Complex (long value) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index 418a565dbd812e..628c40d681bada 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -1865,6 +1865,14 @@ public static explicit operator Half(BigInteger value) return (Half)(double)value; } + /// Explicitly converts a big integer to a value. + /// The value to convert. + /// converted to value. + public static explicit operator BFloat16(BigInteger value) + { + return (BFloat16)(double)value; + } + public static explicit operator short(BigInteger value) { return checked((short)((int)value)); @@ -2118,6 +2126,14 @@ public static explicit operator BigInteger(Half value) return new BigInteger((float)value); } + /// Explicitly converts a value to a big integer. + /// The value to convert. + /// converted to a big integer. + public static explicit operator BigInteger(BFloat16 value) + { + return new BigInteger((float)value); + } + /// Explicitly converts a value to a big integer. /// The value to convert. /// converted to a big integer. @@ -4189,6 +4205,12 @@ private static bool TryConvertFromChecked(TOther value, out BigInteger r result = checked((BigInteger)actualValue); return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = checked((BigInteger)actualValue); + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -4306,6 +4328,12 @@ private static bool TryConvertFromSaturating(TOther value, out BigIntege result = Half.IsNaN(actualValue) ? Zero : (BigInteger)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = BFloat16.IsNaN(actualValue) ? Zero : (BigInteger)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -4423,6 +4451,12 @@ private static bool TryConvertFromTruncating(TOther value, out BigIntege result = Half.IsNaN(actualValue) ? Zero : (BigInteger)actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = BFloat16.IsNaN(actualValue) ? Zero : (BigInteger)actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -4536,6 +4570,12 @@ static bool INumberBase.TryConvertToChecked(BigInteger value result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -4678,6 +4718,12 @@ static bool INumberBase.TryConvertToSaturating(BigInteger va result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult; @@ -4883,6 +4929,12 @@ static bool INumberBase.TryConvertToTruncating(BigInteger va result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult; diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs index e162bab1738051..23530f1f7c4784 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs @@ -832,6 +832,14 @@ public static implicit operator Complex(Half value) return new Complex((double)value, 0.0); } + /// Implicitly converts a value to a double-precision complex number. + /// The value to convert. + /// converted to a double-precision complex number. + public static implicit operator Complex(BFloat16 value) + { + return new Complex((double)value, 0.0); + } + public static implicit operator Complex(short value) { return new Complex(value, 0.0); @@ -1528,6 +1536,12 @@ private static bool TryConvertFrom(TOther value, out Complex result) result = actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1661,6 +1675,12 @@ static bool INumberBase.TryConvertToChecked(Complex value, [May result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (value.m_imaginary != 0) ? BFloat16.NaN : (BFloat16)value.m_real; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { if (value.m_imaginary != 0) @@ -1854,6 +1874,12 @@ static bool INumberBase.TryConvertToSaturating(Complex value, [ result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value.m_real; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value.m_real >= short.MaxValue) ? short.MaxValue : @@ -1990,6 +2016,12 @@ static bool INumberBase.TryConvertToTruncating(Complex value, [ result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value.m_real; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value.m_real >= short.MaxValue) ? short.MaxValue : From fb88f8e9249b92a35699ff700c787c76fd7ec9c2 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 7 Feb 2025 02:31:39 +0800 Subject: [PATCH 59/67] Use float member function instead of MathF --- .../src/System/Numerics/BFloat16.cs | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) 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 ad8df5bf9b9f7c..cac105cf64082b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -836,7 +836,7 @@ public static bool IsPow2(BFloat16 value) } /// - public static BFloat16 Log2(BFloat16 value) => (BFloat16)MathF.Log2((float)value); + public static BFloat16 Log2(BFloat16 value) => (BFloat16)float.Log2((float)value); // // IBitwiseOperators @@ -890,7 +890,7 @@ public static bool IsPow2(BFloat16 value) // /// - public static BFloat16 Exp(BFloat16 x) => (BFloat16)MathF.Exp((float)x); + public static BFloat16 Exp(BFloat16 x) => (BFloat16)float.Exp((float)x); /// public static BFloat16 ExpM1(BFloat16 x) => (BFloat16)float.ExpM1((float)x); @@ -912,25 +912,25 @@ public static bool IsPow2(BFloat16 value) // /// - public static BFloat16 Ceiling(BFloat16 x) => (BFloat16)MathF.Ceiling((float)x); + public static BFloat16 Ceiling(BFloat16 x) => (BFloat16)float.Ceiling((float)x); /// - public static BFloat16 Floor(BFloat16 x) => (BFloat16)MathF.Floor((float)x); + public static BFloat16 Floor(BFloat16 x) => (BFloat16)float.Floor((float)x); /// - public static BFloat16 Round(BFloat16 x) => (BFloat16)MathF.Round((float)x); + public static BFloat16 Round(BFloat16 x) => (BFloat16)float.Round((float)x); /// - public static BFloat16 Round(BFloat16 x, int digits) => (BFloat16)MathF.Round((float)x, digits); + public static BFloat16 Round(BFloat16 x, int digits) => (BFloat16)float.Round((float)x, digits); /// - public static BFloat16 Round(BFloat16 x, MidpointRounding mode) => (BFloat16)MathF.Round((float)x, mode); + public static BFloat16 Round(BFloat16 x, MidpointRounding mode) => (BFloat16)float.Round((float)x, mode); /// - public static BFloat16 Round(BFloat16 x, int digits, MidpointRounding mode) => (BFloat16)MathF.Round((float)x, digits, mode); + public static BFloat16 Round(BFloat16 x, int digits, MidpointRounding mode) => (BFloat16)float.Round((float)x, digits, mode); /// - public static BFloat16 Truncate(BFloat16 x) => (BFloat16)MathF.Truncate((float)x); + public static BFloat16 Truncate(BFloat16 x) => (BFloat16)float.Truncate((float)x); /// int IFloatingPoint.GetExponentByteCount() => sizeof(sbyte); @@ -1031,7 +1031,7 @@ bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destina public static BFloat16 NegativeZero => new BFloat16(NegativeZeroBits); /// - public static BFloat16 Atan2(BFloat16 y, BFloat16 x) => (BFloat16)MathF.Atan2((float)y, (float)x); + public static BFloat16 Atan2(BFloat16 y, BFloat16 x) => (BFloat16)float.Atan2((float)y, (float)x); /// public static BFloat16 Atan2Pi(BFloat16 y, BFloat16 x) => (BFloat16)float.Atan2Pi((float)y, (float)x); @@ -1103,10 +1103,10 @@ public static BFloat16 BitIncrement(BFloat16 x) } /// - public static BFloat16 FusedMultiplyAdd(BFloat16 left, BFloat16 right, BFloat16 addend) => (BFloat16)MathF.FusedMultiplyAdd((float)left, (float)right, (float)addend); + public static BFloat16 FusedMultiplyAdd(BFloat16 left, BFloat16 right, BFloat16 addend) => (BFloat16)float.FusedMultiplyAdd((float)left, (float)right, (float)addend); /// - public static BFloat16 Ieee754Remainder(BFloat16 left, BFloat16 right) => (BFloat16)MathF.IEEERemainder((float)left, (float)right); + public static BFloat16 Ieee754Remainder(BFloat16 left, BFloat16 right) => (BFloat16)float.Ieee754Remainder((float)left, (float)right); /// public static int ILogB(BFloat16 x) @@ -1140,38 +1140,38 @@ public static int ILogB(BFloat16 x) public static BFloat16 Lerp(BFloat16 value1, BFloat16 value2, BFloat16 amount) => (BFloat16)float.Lerp((float)value1, (float)value2, (float)amount); /// - public static BFloat16 ReciprocalEstimate(BFloat16 x) => (BFloat16)MathF.ReciprocalEstimate((float)x); + public static BFloat16 ReciprocalEstimate(BFloat16 x) => (BFloat16)float.ReciprocalEstimate((float)x); /// - public static BFloat16 ReciprocalSqrtEstimate(BFloat16 x) => (BFloat16)MathF.ReciprocalSqrtEstimate((float)x); + public static BFloat16 ReciprocalSqrtEstimate(BFloat16 x) => (BFloat16)float.ReciprocalSqrtEstimate((float)x); /// - public static BFloat16 ScaleB(BFloat16 x, int n) => (BFloat16)MathF.ScaleB((float)x, n); + public static BFloat16 ScaleB(BFloat16 x, int n) => (BFloat16)float.ScaleB((float)x, n); // /// - // public static BFloat16 Compound(BFloat16 x, BFloat16 n) => (BFloat16)MathF.Compound((float)x, (float)n); + // public static BFloat16 Compound(BFloat16 x, BFloat16 n) => (BFloat16)float.Compound((float)x, (float)n); // // IHyperbolicFunctions // /// - public static BFloat16 Acosh(BFloat16 x) => (BFloat16)MathF.Acosh((float)x); + public static BFloat16 Acosh(BFloat16 x) => (BFloat16)float.Acosh((float)x); /// - public static BFloat16 Asinh(BFloat16 x) => (BFloat16)MathF.Asinh((float)x); + public static BFloat16 Asinh(BFloat16 x) => (BFloat16)float.Asinh((float)x); /// - public static BFloat16 Atanh(BFloat16 x) => (BFloat16)MathF.Atanh((float)x); + public static BFloat16 Atanh(BFloat16 x) => (BFloat16)float.Atanh((float)x); /// - public static BFloat16 Cosh(BFloat16 x) => (BFloat16)MathF.Cosh((float)x); + public static BFloat16 Cosh(BFloat16 x) => (BFloat16)float.Cosh((float)x); /// - public static BFloat16 Sinh(BFloat16 x) => (BFloat16)MathF.Sinh((float)x); + public static BFloat16 Sinh(BFloat16 x) => (BFloat16)float.Sinh((float)x); /// - public static BFloat16 Tanh(BFloat16 x) => (BFloat16)MathF.Tanh((float)x); + public static BFloat16 Tanh(BFloat16 x) => (BFloat16)float.Tanh((float)x); // // IIncrementOperators @@ -1190,13 +1190,13 @@ public static int ILogB(BFloat16 x) // /// - public static BFloat16 Log(BFloat16 x) => (BFloat16)MathF.Log((float)x); + public static BFloat16 Log(BFloat16 x) => (BFloat16)float.Log((float)x); /// - public static BFloat16 Log(BFloat16 x, BFloat16 newBase) => (BFloat16)MathF.Log((float)x, (float)newBase); + public static BFloat16 Log(BFloat16 x, BFloat16 newBase) => (BFloat16)float.Log((float)x, (float)newBase); /// - public static BFloat16 Log10(BFloat16 x) => (BFloat16)MathF.Log10((float)x); + public static BFloat16 Log10(BFloat16 x) => (BFloat16)float.Log10((float)x); /// public static BFloat16 LogP1(BFloat16 x) => (BFloat16)float.LogP1((float)x); @@ -1249,7 +1249,7 @@ public static BFloat16 CopySign(BFloat16 value, BFloat16 sign) } /// - public static BFloat16 Max(BFloat16 x, BFloat16 y) => (BFloat16)MathF.Max((float)x, (float)y); + public static BFloat16 Max(BFloat16 x, BFloat16 y) => (BFloat16)float.Max((float)x, (float)y); /// public static BFloat16 MaxNumber(BFloat16 x, BFloat16 y) @@ -1274,7 +1274,7 @@ public static BFloat16 MaxNumber(BFloat16 x, BFloat16 y) } /// - public static BFloat16 Min(BFloat16 x, BFloat16 y) => (BFloat16)MathF.Min((float)x, (float)y); + public static BFloat16 Min(BFloat16 x, BFloat16 y) => (BFloat16)float.Min((float)x, (float)y); /// public static BFloat16 MinNumber(BFloat16 x, BFloat16 y) @@ -1427,7 +1427,7 @@ public static bool IsRealNumber(BFloat16 value) static bool INumberBase.IsZero(BFloat16 value) => IsZero(value); /// - public static BFloat16 MaxMagnitude(BFloat16 x, BFloat16 y) => (BFloat16)MathF.MaxMagnitude((float)x, (float)y); + public static BFloat16 MaxMagnitude(BFloat16 x, BFloat16 y) => (BFloat16)float.MaxMagnitude((float)x, (float)y); /// public static BFloat16 MaxMagnitudeNumber(BFloat16 x, BFloat16 y) @@ -1455,7 +1455,7 @@ public static BFloat16 MaxMagnitudeNumber(BFloat16 x, BFloat16 y) } /// - public static BFloat16 MinMagnitude(BFloat16 x, BFloat16 y) => (BFloat16)MathF.MinMagnitude((float)x, (float)y); + public static BFloat16 MinMagnitude(BFloat16 x, BFloat16 y) => (BFloat16)float.MinMagnitude((float)x, (float)y); /// public static BFloat16 MinMagnitudeNumber(BFloat16 x, BFloat16 y) @@ -1814,14 +1814,14 @@ private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] // /// - public static BFloat16 Pow(BFloat16 x, BFloat16 y) => (BFloat16)MathF.Pow((float)x, (float)y); + public static BFloat16 Pow(BFloat16 x, BFloat16 y) => (BFloat16)float.Pow((float)x, (float)y); // // IRootFunctions // /// - public static BFloat16 Cbrt(BFloat16 x) => (BFloat16)MathF.Cbrt((float)x); + public static BFloat16 Cbrt(BFloat16 x) => (BFloat16)float.Cbrt((float)x); /// public static BFloat16 Hypot(BFloat16 x, BFloat16 y) => (BFloat16)float.Hypot((float)x, (float)y); @@ -1830,7 +1830,7 @@ private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] public static BFloat16 RootN(BFloat16 x, int n) => (BFloat16)float.RootN((float)x, n); /// - public static BFloat16 Sqrt(BFloat16 x) => (BFloat16)MathF.Sqrt((float)x); + public static BFloat16 Sqrt(BFloat16 x) => (BFloat16)float.Sqrt((float)x); // // ISignedNumber @@ -1861,25 +1861,25 @@ private static bool TryConvertTo(BFloat16 value, [MaybeNullWhen(false)] // /// - public static BFloat16 Acos(BFloat16 x) => (BFloat16)MathF.Acos((float)x); + public static BFloat16 Acos(BFloat16 x) => (BFloat16)float.Acos((float)x); /// public static BFloat16 AcosPi(BFloat16 x) => (BFloat16)float.AcosPi((float)x); /// - public static BFloat16 Asin(BFloat16 x) => (BFloat16)MathF.Asin((float)x); + public static BFloat16 Asin(BFloat16 x) => (BFloat16)float.Asin((float)x); /// public static BFloat16 AsinPi(BFloat16 x) => (BFloat16)float.AsinPi((float)x); /// - public static BFloat16 Atan(BFloat16 x) => (BFloat16)MathF.Atan((float)x); + public static BFloat16 Atan(BFloat16 x) => (BFloat16)float.Atan((float)x); /// public static BFloat16 AtanPi(BFloat16 x) => (BFloat16)float.AtanPi((float)x); /// - public static BFloat16 Cos(BFloat16 x) => (BFloat16)MathF.Cos((float)x); + public static BFloat16 Cos(BFloat16 x) => (BFloat16)float.Cos((float)x); /// public static BFloat16 CosPi(BFloat16 x) => (BFloat16)float.CosPi((float)x); @@ -1903,12 +1903,12 @@ public static BFloat16 RadiansToDegrees(BFloat16 radians) } /// - public static BFloat16 Sin(BFloat16 x) => (BFloat16)MathF.Sin((float)x); + public static BFloat16 Sin(BFloat16 x) => (BFloat16)float.Sin((float)x); /// public static (BFloat16 Sin, BFloat16 Cos) SinCos(BFloat16 x) { - var (sin, cos) = MathF.SinCos((float)x); + var (sin, cos) = float.SinCos((float)x); return ((BFloat16)sin, (BFloat16)cos); } @@ -1923,7 +1923,7 @@ public static (BFloat16 SinPi, BFloat16 CosPi) SinCosPi(BFloat16 x) public static BFloat16 SinPi(BFloat16 x) => (BFloat16)float.SinPi((float)x); /// - public static BFloat16 Tan(BFloat16 x) => (BFloat16)MathF.Tan((float)x); + public static BFloat16 Tan(BFloat16 x) => (BFloat16)float.Tan((float)x); /// public static BFloat16 TanPi(BFloat16 x) => (BFloat16)float.TanPi((float)x); From d69734499ea3cf99db3adc7b88dec510616a4fd0 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 7 Feb 2025 21:04:53 +0800 Subject: [PATCH 60/67] Fill conversion in decimal --- .../System.Private.CoreLib/src/System/Decimal.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs index c9e03939b8ae82..914f2c112137ce 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs @@ -1660,6 +1660,12 @@ static bool INumberBase.TryConvertToChecked(decimal value, [May result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = checked((BFloat16)value); + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -1748,6 +1754,12 @@ private static bool TryConvertTo(decimal value, [MaybeNullWhen(false)] o result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= short.MaxValue) ? short.MaxValue : From 4e83ad9ab70172d14690056afe6dbfa203601165 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 7 Feb 2025 21:16:09 +0800 Subject: [PATCH 61/67] Add conversion for NFloat --- .../System/Runtime/InteropServices/NFloat.cs | 30 +++++++++++++++++++ .../ref/System.Runtime.InteropServices.cs | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index 5e2fb905df195c..f062c78174a89c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -287,6 +287,12 @@ public double Value [NonVersionable] public static explicit operator Half(NFloat value) => (Half)(value._value); + /// Explicitly converts a native-sized floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [NonVersionable] + public static explicit operator BFloat16(NFloat value) => (BFloat16)(value._value); + /// Explicitly converts a native-sized floating-point value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. @@ -470,6 +476,12 @@ public double Value [NonVersionable] public static implicit operator NFloat(Half value) => (NFloat)(float)value; + /// Implicitly converts a value to its nearest representable native-sized floating-point value. + /// The value to convert. + /// converted to its nearest representable native-sized floating-point value. + [NonVersionable] + public static implicit operator NFloat(BFloat16 value) => (NFloat)(float)value; + /// Implicitly converts a value to its nearest representable native-sized floating-point value. /// The value to convert. /// converted to its nearest representable native-sized floating-point value. @@ -1444,6 +1456,12 @@ private static bool TryConvertFrom(TOther value, out NFloat result) result = actualValue; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualValue = (BFloat16)(object)value; + result = actualValue; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualValue = (short)(object)value; @@ -1557,6 +1575,12 @@ static bool INumberBase.TryConvertToChecked(NFloat value, [Maybe result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = checked((short)value); @@ -1688,6 +1712,12 @@ private static bool TryConvertTo(NFloat value, [MaybeNullWhen(false)] ou result = (TOther)(object)actualResult; return true; } + else if (typeof(TOther) == typeof(BFloat16)) + { + BFloat16 actualResult = (BFloat16)value; + result = (TOther)(object)actualResult; + return true; + } else if (typeof(TOther) == typeof(short)) { short actualResult = (value >= short.MaxValue) ? short.MaxValue : diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 4fa55777f5327c..e08112291ded87 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -1433,6 +1433,7 @@ public static void Free(void* ptr) { } public static explicit operator char (System.Runtime.InteropServices.NFloat value) { throw null; } public static explicit operator decimal (System.Runtime.InteropServices.NFloat value) { throw null; } public static explicit operator System.Half (System.Runtime.InteropServices.NFloat value) { throw null; } + public static explicit operator System.Numerics.BFloat16 (System.Runtime.InteropServices.NFloat value) { throw null; } public static explicit operator System.Int128 (System.Runtime.InteropServices.NFloat value) { throw null; } public static explicit operator short (System.Runtime.InteropServices.NFloat value) { throw null; } public static explicit operator int (System.Runtime.InteropServices.NFloat value) { throw null; } @@ -1462,6 +1463,7 @@ public static void Free(void* ptr) { } public static implicit operator System.Runtime.InteropServices.NFloat (long value) { throw null; } public static implicit operator System.Runtime.InteropServices.NFloat (nint value) { throw null; } public static implicit operator System.Runtime.InteropServices.NFloat (System.Half value) { throw null; } + public static implicit operator System.Runtime.InteropServices.NFloat (System.Numerics.BFloat16 value) { throw null; } public static implicit operator double (System.Runtime.InteropServices.NFloat value) { throw null; } [System.CLSCompliantAttribute(false)] public static implicit operator System.Runtime.InteropServices.NFloat (sbyte value) { throw null; } From d58c80adae8a6896200b7034bbb131023e2d4aec Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 10 Feb 2025 01:03:22 +0800 Subject: [PATCH 62/67] Use soft rounding for uint->bf16 --- .../System.Private.CoreLib/src/System/Half.cs | 2 +- .../src/System/Numerics/BFloat16.cs | 61 ++++++++++++++----- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 0d5ef2b3206c8e..d459b5be53b5fa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1177,7 +1177,7 @@ private static double CreateDoubleNaN(bool sign, ulong significand) return BitConverter.UInt64BitsToDouble(signInt | NaNBits | sigInt); } - private static float CreateSingle(bool sign, byte exp, uint sig) => BitConverter.UInt32BitsToSingle(((sign ? 1U : 0U) << float.SignShift) + ((uint)exp << float.BiasedExponentShift) + sig); + internal static float CreateSingle(bool sign, byte exp, uint sig) => BitConverter.UInt32BitsToSingle(((sign ? 1U : 0U) << float.SignShift) + ((uint)exp << float.BiasedExponentShift) + sig); private static double CreateDouble(bool sign, ushort exp, ulong sig) => BitConverter.UInt64BitsToDouble(((sign ? 1UL : 0UL) << double.SignShift) + ((ulong)exp << double.BiasedExponentShift) + sig); 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 cac105cf64082b..419f6c83559c7e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -545,20 +545,10 @@ public static explicit operator BFloat16(double value) public static explicit operator BFloat16(float value) { uint bits = BitConverter.SingleToUInt32Bits(value); - uint upper = bits >> 16; - // Only do rounding for finite numbers - if (float.IsFinite(value)) - { - uint lower = (ushort)bits; - // Determine the increment for rounding - // When upper is even, midpoint (0x8000) will tie to no increment, which is effectively a decrement of lower - uint lowerShift = (~upper) & (lower >> 15) & 1; // Upper is even & lower>=0x8000 (not 0) - lower -= lowerShift; - uint increment = lower >> 15; - // Do the increment, MaxValue will be correctly increased to Infinity - upper += increment; - } - return new BFloat16((ushort)upper); + uint roundedBits = RoundMidpointToEven(bits, 16); + + // Only do rounding for non-NaN + return new BFloat16((ushort)(!float.IsNaN(value) ? roundedBits : (bits >> 16))); } /// Explicitly converts a value to its nearest representable value. @@ -567,11 +557,52 @@ public static explicit operator BFloat16(float value) [CLSCompliant(false)] public static explicit operator BFloat16(ushort value) => (BFloat16)(float)value; + /// + /// Rounds a number to shorter length with the midpoint-to-even rule. + /// + /// The unsigned integer type to operate with. + /// The payload number. Can be either actual unsigned integer, or (non-NaN) IEEE754 binary fp type. + /// The length of trailing bits to round up. Should be constant. + /// Rounded payload bits, right shifted by and aligns to LSB. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TInteger RoundMidpointToEven(TInteger value, int trailingLength) + where TInteger : unmanaged, IBinaryInteger, IUnsignedNumber + { + TInteger lower = value & ((TInteger.One << trailingLength) - TInteger.One); + TInteger upper = value >>> trailingLength; + + // Determine the increment for rounding + // When upper is even, midpoint will tie to no increment, which is effectively a decrement of lower + TInteger lowerShift = (~upper) & (lower >> (trailingLength - 1)) & TInteger.One; // Upper is even & lower>=midpoint (not 0) + lower -= lowerShift; + TInteger increment = lower >> (trailingLength - 1); + // Do the increment, MaxValue will be correctly increased to Infinity + upper += increment; + + return upper; + } + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. [CLSCompliant(false)] - public static explicit operator BFloat16(uint value) => (BFloat16)(float)value; + public static explicit operator BFloat16(uint value) + { + uint scale = uint.LeadingZeroCount(value); + uint alignedValue = value << (int)scale; + uint significandBits = RoundMidpointToEven(alignedValue, 32 - SignificandLength); + + // Leverage FPU to calculate the value significandBits * 2^(32-SignificandLength-scale), for proper handling of 0 and carrying + // Use int->float conversion which usually has better FPU support + float significand = (float)(int)significandBits; + // Craft the value 2^(32-SignificandLength-scale) + float scaleFactor = Half.CreateSingle(false, (byte)(32 - SignificandLength - scale + float.ExponentBias), 0); + float roundedValue = significand * scaleFactor; + + uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); + Debug.Assert((ushort)roundedValueBits == 0); // The value should be properly rounded + return new BFloat16((ushort)(roundedValueBits >> 16)); + } /// Explicitly converts a value to its nearest representable value. /// The value to convert. From 8639fa3a25f80838c62ae0c64a0680050741fd44 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 10 Feb 2025 11:26:23 +0800 Subject: [PATCH 63/67] Generic math rounding from unsigned and signed integer --- .../src/System/Numerics/BFloat16.cs | 119 +++++++++++------- 1 file changed, 72 insertions(+), 47 deletions(-) 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 419f6c83559c7e..7c34340283e602 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -509,6 +509,53 @@ public static explicit operator BFloat16(double value) return new BFloat16((ushort)bitValue); } + /// + /// Rounds a number to shorter length with the midpoint-to-even rule. + /// + /// The integer type to operate with. + /// The payload number. Can be either actual unsigned integer, or (non-NaN) IEEE754 binary fp type. + /// The length of trailing bits to round up. Should be constant. + /// Rounded payload bits, right shifted by and aligns to LSB. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TInteger RoundMidpointToEven(TInteger value, int trailingLength) + where TInteger : unmanaged, IBinaryInteger + { + TInteger lower = value & ((TInteger.One << trailingLength) - TInteger.One); + TInteger upper = value >>> trailingLength; + + // Determine the increment for rounding + // When upper is even, midpoint will tie to no increment, which is effectively a decrement of lower + TInteger lowerShift = (~upper) & (lower >>> (trailingLength - 1)) & TInteger.One; // Upper is even & lower>=midpoint (not 0) + lower -= lowerShift; + TInteger increment = lower >>> (trailingLength - 1); + // Do the increment, MaxValue will be correctly increased to Infinity + upper += increment; + + return upper; + } + + private static unsafe BFloat16 RoundFromSigned(TInteger value) + where TInteger : unmanaged, IBinaryInteger, ISignedNumber + { + bool sign = TInteger.IsNegative(value); + TInteger abs = TInteger.IsNegative(value) ? -value : value; + + int scale = int.CreateTruncating(TInteger.LeadingZeroCount(abs)); + TInteger alignedValue = abs << scale; + TInteger significandBits = RoundMidpointToEven(alignedValue, sizeof(TInteger) * 8 - SignificandLength); + + // Leverage FPU to calculate the value significandBits * 2^(32-SignificandLength-scale), for proper handling of 0 and carrying + // Use int->float conversion which usually has better FPU support + float significand = (float)int.CreateTruncating(significandBits); + // Craft the value 2^(32-SignificandLength-scale) + float scaleFactor = Half.CreateSingle(sign, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); + float roundedValue = significand * scaleFactor; + + uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); + Debug.Assert((ushort)roundedValueBits == 0); // The value should be properly rounded + return new BFloat16((ushort)(roundedValueBits >> 16)); + } + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. @@ -522,22 +569,22 @@ public static explicit operator BFloat16(double value) /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(int value) => (BFloat16)(float)value; + public static explicit operator BFloat16(int value) => RoundFromSigned(value); /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(long value) => (BFloat16)(float)value; + public static explicit operator BFloat16(long value) => RoundFromSigned(value); /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(Int128 value) => (BFloat16)(float)value; + public static explicit operator BFloat16(Int128 value) => RoundFromSigned(value); /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. - public static explicit operator BFloat16(nint value) => (BFloat16)(float)value; + public static explicit operator BFloat16(nint value) => RoundFromSigned(value); /// Explicitly converts a value to its nearest representable value. /// The value to convert. @@ -551,52 +598,18 @@ public static explicit operator BFloat16(float value) return new BFloat16((ushort)(!float.IsNaN(value) ? roundedBits : (bits >> 16))); } - /// Explicitly converts a value to its nearest representable value. - /// The value to convert. - /// converted to its nearest representable value. - [CLSCompliant(false)] - public static explicit operator BFloat16(ushort value) => (BFloat16)(float)value; - - /// - /// Rounds a number to shorter length with the midpoint-to-even rule. - /// - /// The unsigned integer type to operate with. - /// The payload number. Can be either actual unsigned integer, or (non-NaN) IEEE754 binary fp type. - /// The length of trailing bits to round up. Should be constant. - /// Rounded payload bits, right shifted by and aligns to LSB. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static TInteger RoundMidpointToEven(TInteger value, int trailingLength) + private static unsafe BFloat16 RoundFromUnsigned(TInteger value) where TInteger : unmanaged, IBinaryInteger, IUnsignedNumber { - TInteger lower = value & ((TInteger.One << trailingLength) - TInteger.One); - TInteger upper = value >>> trailingLength; - - // Determine the increment for rounding - // When upper is even, midpoint will tie to no increment, which is effectively a decrement of lower - TInteger lowerShift = (~upper) & (lower >> (trailingLength - 1)) & TInteger.One; // Upper is even & lower>=midpoint (not 0) - lower -= lowerShift; - TInteger increment = lower >> (trailingLength - 1); - // Do the increment, MaxValue will be correctly increased to Infinity - upper += increment; - - return upper; - } - - /// Explicitly converts a value to its nearest representable value. - /// The value to convert. - /// converted to its nearest representable value. - [CLSCompliant(false)] - public static explicit operator BFloat16(uint value) - { - uint scale = uint.LeadingZeroCount(value); - uint alignedValue = value << (int)scale; - uint significandBits = RoundMidpointToEven(alignedValue, 32 - SignificandLength); + int scale = int.CreateTruncating(TInteger.LeadingZeroCount(value)); + TInteger alignedValue = value << scale; + TInteger significandBits = RoundMidpointToEven(alignedValue, sizeof(TInteger) * 8 - SignificandLength); // Leverage FPU to calculate the value significandBits * 2^(32-SignificandLength-scale), for proper handling of 0 and carrying // Use int->float conversion which usually has better FPU support - float significand = (float)(int)significandBits; + float significand = (float)int.CreateTruncating(significandBits); // Craft the value 2^(32-SignificandLength-scale) - float scaleFactor = Half.CreateSingle(false, (byte)(32 - SignificandLength - scale + float.ExponentBias), 0); + float scaleFactor = Half.CreateSingle(false, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); float roundedValue = significand * scaleFactor; uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); @@ -604,23 +617,35 @@ public static explicit operator BFloat16(uint value) return new BFloat16((ushort)(roundedValueBits >> 16)); } + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator BFloat16(ushort value) => RoundFromUnsigned(value); + + /// Explicitly converts a value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator BFloat16(uint value) => RoundFromUnsigned(value); + /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. [CLSCompliant(false)] - public static explicit operator BFloat16(ulong value) => (BFloat16)(float)value; + public static explicit operator BFloat16(ulong value) => RoundFromUnsigned(value); /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. [CLSCompliant(false)] - public static explicit operator BFloat16(nuint value) => (BFloat16)(float)value; + public static explicit operator BFloat16(nuint value) => RoundFromUnsigned(value); /// Explicitly converts a value to its nearest representable value. /// The value to convert. /// converted to its nearest representable value. [CLSCompliant(false)] - public static explicit operator BFloat16(UInt128 value) => (BFloat16)(float)value; + public static explicit operator BFloat16(UInt128 value) => RoundFromUnsigned(value); // // Explicit Convert From BFloat16 From 34b1d0742095351f87c8a555ffa55ba7d2bf4253 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 11 Feb 2025 02:18:22 +0800 Subject: [PATCH 64/67] Cleanup helper methods --- .../System.Private.CoreLib/src/System/BitConverter.cs | 9 +++++++++ .../System.Private.CoreLib/src/System/Double.cs | 2 +- src/libraries/System.Private.CoreLib/src/System/Half.cs | 6 +----- .../System.Private.CoreLib/src/System/Int128.cs | 8 ++++---- src/libraries/System.Private.CoreLib/src/System/Int16.cs | 8 ++++---- src/libraries/System.Private.CoreLib/src/System/Int32.cs | 8 ++++---- src/libraries/System.Private.CoreLib/src/System/Int64.cs | 8 ++++---- src/libraries/System.Private.CoreLib/src/System/Math.cs | 4 ++++ .../src/System/Numerics/BFloat16.cs | 4 ++-- 9 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs b/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs index 0fcd264414fe29..1e387c90c75389 100644 --- a/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; @@ -934,6 +935,10 @@ public static bool ToBoolean(ReadOnlySpan value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Int16BitsToHalf(short value) => new Half((ushort)(value)); + internal static short BFloat16BitsToInt16(BFloat16 value) => (short)value._value; + + internal static BFloat16 Int16BitsToBFloat16(short value) => new BFloat16((ushort)(value)); + /// /// Converts the specified double-precision floating point number to a 64-bit unsigned integer. /// @@ -987,5 +992,9 @@ public static bool ToBoolean(ReadOnlySpan value) [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half UInt16BitsToHalf(ushort value) => new Half(value); + + internal static ushort BFloat16BitsToUInt16(BFloat16 value) => value._value; + + internal static BFloat16 UInt16BitsToBFloat16(ushort value) => new BFloat16(value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index fc000b8df3ddf8..ae1de4c6ae7054 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -1248,7 +1248,7 @@ private static bool TryConvertFrom(TOther value, out double result) result = (double)actualValue; return true; } - if (typeof(TOther) == typeof(BFloat16)) + else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; result = (double)actualValue; diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index d459b5be53b5fa..e12bf50fb5dbfb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1015,7 +1015,7 @@ public static explicit operator double(Half value) exp -= 1; } - return CreateDouble(sign, (ushort)(exp + 0x3F0), (ulong)sig << 42); + return Math.CreateDouble(sign, (ushort)(exp + 0x3F0), (ulong)sig << 42); } /// Explicitly converts a half-precision floating-point value to its nearest representable value. @@ -1177,10 +1177,6 @@ private static double CreateDoubleNaN(bool sign, ulong significand) return BitConverter.UInt64BitsToDouble(signInt | NaNBits | sigInt); } - internal static float CreateSingle(bool sign, byte exp, uint sig) => BitConverter.UInt32BitsToSingle(((sign ? 1U : 0U) << float.SignShift) + ((uint)exp << float.BiasedExponentShift) + sig); - - private static double CreateDouble(bool sign, ushort exp, ulong sig) => BitConverter.UInt64BitsToDouble(((sign ? 1UL : 0UL) << double.SignShift) + ((ulong)exp << double.BiasedExponentShift) + sig); - #endregion // diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 56331fadf8c32c..89a11b9426fe34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -1604,8 +1604,8 @@ private static bool TryConvertFromSaturating(TOther value, out Int128 re else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x7F00)) ? MaxValue : - (actualValue <= new BFloat16(0xFF00)) ? MinValue : (Int128)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x7F00)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xFF00)) ? MinValue : (Int128)actualValue; return true; } else if (typeof(TOther) == typeof(short)) @@ -1686,8 +1686,8 @@ private static bool TryConvertFromTruncating(TOther value, out Int128 re else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x7F00)) ? MaxValue : - (actualValue <= new BFloat16(0xFF00)) ? MinValue : (Int128)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x7F00)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xFF00)) ? MinValue : (Int128)actualValue; return true; } else if (typeof(TOther) == typeof(short)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index de9296d1f66db6..cb128c7f2875ff 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -981,8 +981,8 @@ private static bool TryConvertFromSaturating(TOther value, out short res else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x4700)) ? MaxValue : - (actualValue <= new BFloat16(0xB700)) ? MinValue : (short)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4700)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xB700)) ? MinValue : (short)actualValue; return true; } else if (typeof(TOther) == typeof(int)) @@ -1067,8 +1067,8 @@ private static bool TryConvertFromTruncating(TOther value, out short res else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x4700)) ? MaxValue : - (actualValue <= new BFloat16(0xB700)) ? MinValue : (short)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4700)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xB700)) ? MinValue : (short)actualValue; return true; } else if (typeof(TOther) == typeof(int)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index 548faf6a182464..d5caff910d55e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -1022,8 +1022,8 @@ private static bool TryConvertFromSaturating(TOther value, out int resul else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x4F00)) ? MaxValue : - (actualValue <= new BFloat16(0xBF00)) ? MinValue : (int)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4F00)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xBF00)) ? MinValue : (int)actualValue; return true; } else if (typeof(TOther) == typeof(short)) @@ -1107,8 +1107,8 @@ private static bool TryConvertFromTruncating(TOther value, out int resul else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x4F00)) ? MaxValue : - (actualValue <= new BFloat16(0xBF00)) ? MinValue : (int)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4F00)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xBF00)) ? MinValue : (int)actualValue; return true; } else if (typeof(TOther) == typeof(short)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index 53fe0eeb0d2156..9bfcfe76fa4b1a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -1019,8 +1019,8 @@ private static bool TryConvertFromSaturating(TOther value, out long resu else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x5F00)) ? MaxValue : - (actualValue <= new BFloat16(0xCF00)) ? MinValue : (long)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x5F00)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xCF00)) ? MinValue : (long)actualValue; return true; } else if (typeof(TOther) == typeof(short)) @@ -1102,8 +1102,8 @@ private static bool TryConvertFromTruncating(TOther value, out long resu else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= new BFloat16(0x5F00)) ? MaxValue : - (actualValue <= new BFloat16(0xCF00)) ? MinValue : (long)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x5F00)) ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xCF00)) ? MinValue : (long)actualValue; return true; } else if (typeof(TOther) == typeof(short)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 9337314de15b01..477b444aca59d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1707,5 +1707,9 @@ internal static ulong ConvertToUInt64Checked(double value) ThrowHelper.ThrowOverflowException(); return 0; } + + internal static float CreateSingle(bool sign, byte exp, uint sig) => BitConverter.UInt32BitsToSingle(((sign ? 1U : 0U) << float.SignShift) + ((uint)exp << float.BiasedExponentShift) + sig); + + internal static double CreateDouble(bool sign, ushort exp, ulong sig) => BitConverter.UInt64BitsToDouble(((sign ? 1UL : 0UL) << double.SignShift) + ((ulong)exp << double.BiasedExponentShift) + sig); } } 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 7c34340283e602..9f290f309a24fa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -548,7 +548,7 @@ private static unsafe BFloat16 RoundFromSigned(TInteger value) // Use int->float conversion which usually has better FPU support float significand = (float)int.CreateTruncating(significandBits); // Craft the value 2^(32-SignificandLength-scale) - float scaleFactor = Half.CreateSingle(sign, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); + float scaleFactor = Math.CreateSingle(sign, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); float roundedValue = significand * scaleFactor; uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); @@ -609,7 +609,7 @@ private static unsafe BFloat16 RoundFromUnsigned(TInteger value) // Use int->float conversion which usually has better FPU support float significand = (float)int.CreateTruncating(significandBits); // Craft the value 2^(32-SignificandLength-scale) - float scaleFactor = Half.CreateSingle(false, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); + float scaleFactor = Math.CreateSingle(false, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); float roundedValue = significand * scaleFactor; uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); From 8adbeb2117f5dd18bf98a833d2295c871948f944 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 11 Feb 2025 03:05:07 +0800 Subject: [PATCH 65/67] Add integer rounding tests --- .../System/Numerics/BFloat16Tests.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) 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 af764c7c887ba5..c88eb34f528bb8 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 @@ -8,6 +8,7 @@ using System.Text; using Xunit; using Xunit.Sdk; +using static System.Tests.CreateDelegateTests; namespace System.Numerics.Tests { @@ -632,6 +633,72 @@ public static IEnumerable ExplicitConversion_FromDouble_TestData() AssertEqual(expected, b16); } + public static IEnumerable ExplicitConversion_FromInt32_TestData() + { + (int, BFloat16)[] data = + { + (-0x103_0001, UInt16BitsToBFloat16(0xCB82)), // -16973824 - 1 rounds lower + (-0x103_0000, UInt16BitsToBFloat16(0xCB82)), // -16973824 rounds to even + (-0x102_FFFF, UInt16BitsToBFloat16(0xCB81)), // -16973824 + 1 rounds higher + (-0x101_0001, UInt16BitsToBFloat16(0xCB81)), // -16842752 - 1 rounds lower + (-0x101_0000, UInt16BitsToBFloat16(0xCB80)), // -16842752 rounds to even + (-0x100_FFFF, UInt16BitsToBFloat16(0xCB80)), // -16842752 + 1 rounds higher + (0, BFloat16.Zero), + (0x100_FFFF, UInt16BitsToBFloat16(0x4B80)), // 16842752 - 1 rounds lower + (0x101_0000, UInt16BitsToBFloat16(0x4B80)), // 16842752 rounds to even + (0x101_0001, UInt16BitsToBFloat16(0x4B81)), // 16842752 + 1 rounds higher + (0x102_FFFF, UInt16BitsToBFloat16(0x4B81)), // 16973824 - 1 rounds lower + (0x103_0000, UInt16BitsToBFloat16(0x4B82)), // 16973824 rounds to even + (0x103_0001, UInt16BitsToBFloat16(0x4B82)), // 16973824 + 1 rounds higher + (int.MinValue, UInt16BitsToBFloat16(0xCF00)), + }; + + foreach ((int original, BFloat16 expected) in data) + { + yield return new object[] { original, expected }; + } + } + + [MemberData(nameof(ExplicitConversion_FromInt32_TestData))] + [Theory] + public static void ExplicitConversion_FromInt32(int i, BFloat16 expected) + { + BFloat16 b16 = (BFloat16)i; + AssertEqual(expected, b16); + } + + public static IEnumerable ExplicitConversion_FromUInt32_TestData() + { + (uint, BFloat16)[] data = + { + (0, BFloat16.Zero), + (0x100_FFFF, UInt16BitsToBFloat16(0x4B80)), // 16842752 - 1 rounds lower + (0x101_0000, UInt16BitsToBFloat16(0x4B80)), // 16842752 rounds to even + (0x101_0001, UInt16BitsToBFloat16(0x4B81)), // 16842752 + 1 rounds higher + (0x102_FFFF, UInt16BitsToBFloat16(0x4B81)), // 16973824 - 1 rounds lower + (0x103_0000, UInt16BitsToBFloat16(0x4B82)), // 16973824 rounds to even + (0x103_0001, UInt16BitsToBFloat16(0x4B82)), // 16973824 + 1 rounds higher + (0x8000_0000, UInt16BitsToBFloat16(0x4F00)), + (0xFF7F_FFFF, UInt16BitsToBFloat16(0x4F7F)), // 4286578688 - 1 rounds lower + (0xFF80_0000, UInt16BitsToBFloat16(0x4F80)), // 4286578688 rounds to even + (0xFF80_0001, UInt16BitsToBFloat16(0x4F80)), // 4286578688 + 1 rounds higher + (0xFFFF_FFFF, UInt16BitsToBFloat16(0x4F80)), + }; + + foreach ((uint original, BFloat16 expected) in data) + { + yield return new object[] { original, expected }; + } + } + + [MemberData(nameof(ExplicitConversion_FromUInt32_TestData))] + [Theory] + public static void ExplicitConversion_FromUInt32(uint i, BFloat16 expected) + { + BFloat16 b16 = (BFloat16)i; + AssertEqual(expected, b16); + } + public static IEnumerable Parse_Valid_TestData() { NumberStyles defaultStyle = NumberStyles.Float | NumberStyles.AllowThousands; From 1f2653f6fc0bcf8888c202cf9659861ded85650f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 11 Feb 2025 13:19:51 +0800 Subject: [PATCH 66/67] Move helpers and fix comment --- .../System.Private.CoreLib/src/System/Double.cs | 2 ++ .../System.Private.CoreLib/src/System/Half.cs | 2 +- .../System.Private.CoreLib/src/System/Math.cs | 4 ---- .../src/System/Numerics/BFloat16.cs | 14 +++++++------- .../System.Private.CoreLib/src/System/Single.cs | 2 ++ 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index ae1de4c6ae7054..6199a5226fe195 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -162,6 +162,8 @@ internal static ulong ExtractTrailingSignificandFromBits(ulong bits) return bits & TrailingSignificandMask; } + internal static double CreateDouble(bool sign, ushort exp, ulong sig) => BitConverter.UInt64BitsToDouble(((sign ? 1UL : 0UL) << double.SignShift) + ((ulong)exp << double.BiasedExponentShift) + sig); + /// Determines whether the specified value is finite (zero, subnormal, or normal). /// This effectively checks the value is not NaN and not infinite. [NonVersionable] diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index e12bf50fb5dbfb..8d41a724b14683 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1015,7 +1015,7 @@ public static explicit operator double(Half value) exp -= 1; } - return Math.CreateDouble(sign, (ushort)(exp + 0x3F0), (ulong)sig << 42); + return double.CreateDouble(sign, (ushort)(exp + 0x3F0), (ulong)sig << 42); } /// Explicitly converts a half-precision floating-point value to its nearest representable value. diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 477b444aca59d0..9337314de15b01 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1707,9 +1707,5 @@ internal static ulong ConvertToUInt64Checked(double value) ThrowHelper.ThrowOverflowException(); return 0; } - - internal static float CreateSingle(bool sign, byte exp, uint sig) => BitConverter.UInt32BitsToSingle(((sign ? 1U : 0U) << float.SignShift) + ((uint)exp << float.BiasedExponentShift) + sig); - - internal static double CreateDouble(bool sign, ushort exp, ulong sig) => BitConverter.UInt64BitsToDouble(((sign ? 1UL : 0UL) << double.SignShift) + ((ulong)exp << double.BiasedExponentShift) + sig); } } 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 9f290f309a24fa..3466fd09189a2d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -544,11 +544,11 @@ private static unsafe BFloat16 RoundFromSigned(TInteger value) TInteger alignedValue = abs << scale; TInteger significandBits = RoundMidpointToEven(alignedValue, sizeof(TInteger) * 8 - SignificandLength); - // Leverage FPU to calculate the value significandBits * 2^(32-SignificandLength-scale), for proper handling of 0 and carrying + // Leverage FPU to calculate the value significandBits * 2^(size-SignificandLength-scale), for proper handling of 0 and carrying // Use int->float conversion which usually has better FPU support float significand = (float)int.CreateTruncating(significandBits); - // Craft the value 2^(32-SignificandLength-scale) - float scaleFactor = Math.CreateSingle(sign, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); + // Craft the value 2^(size-SignificandLength-scale) + float scaleFactor = float.CreateSingle(sign, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); float roundedValue = significand * scaleFactor; uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); @@ -605,11 +605,11 @@ private static unsafe BFloat16 RoundFromUnsigned(TInteger value) TInteger alignedValue = value << scale; TInteger significandBits = RoundMidpointToEven(alignedValue, sizeof(TInteger) * 8 - SignificandLength); - // Leverage FPU to calculate the value significandBits * 2^(32-SignificandLength-scale), for proper handling of 0 and carrying + // Leverage FPU to calculate the value significandBits * 2^(size-SignificandLength-scale), for proper handling of 0 and carrying // Use int->float conversion which usually has better FPU support float significand = (float)int.CreateTruncating(significandBits); - // Craft the value 2^(32-SignificandLength-scale) - float scaleFactor = Math.CreateSingle(false, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); + // Craft the value 2^(size-SignificandLength-scale) + float scaleFactor = float.CreateSingle(false, (byte)(sizeof(TInteger) * 8 - SignificandLength - scale + float.ExponentBias), 0); float roundedValue = significand * scaleFactor; uint roundedValueBits = BitConverter.SingleToUInt32Bits(roundedValue); @@ -621,7 +621,7 @@ private static unsafe BFloat16 RoundFromUnsigned(TInteger value) /// The value to convert. /// converted to its nearest representable value. [CLSCompliant(false)] - public static explicit operator BFloat16(ushort value) => RoundFromUnsigned(value); + public static explicit operator BFloat16(ushort value) => (BFloat16)(float)value; /// Explicitly converts a value to its nearest representable value. /// The value to convert. diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 04b036c24561d6..3f6e8a1e741e08 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -162,6 +162,8 @@ internal static uint ExtractTrailingSignificandFromBits(uint bits) return bits & TrailingSignificandMask; } + internal static float CreateSingle(bool sign, byte exp, uint sig) => BitConverter.UInt32BitsToSingle(((sign ? 1U : 0U) << float.SignShift) + ((uint)exp << float.BiasedExponentShift) + sig); + /// Determines whether the specified value is finite (zero, subnormal, or normal). /// This effectively checks the value is not NaN and not infinite. [NonVersionable] From 9046622b88980049c8485545dad280b632e284af Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 11 Feb 2025 14:07:59 +0800 Subject: [PATCH 67/67] Update comment --- src/libraries/System.Private.CoreLib/src/System/Half.cs | 2 +- src/libraries/System.Private.CoreLib/src/System/Int128.cs | 4 ++-- src/libraries/System.Private.CoreLib/src/System/Int16.cs | 8 ++++---- src/libraries/System.Private.CoreLib/src/System/Int32.cs | 4 ++-- src/libraries/System.Private.CoreLib/src/System/Int64.cs | 4 ++-- .../src/System/Numerics/BFloat16.cs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 8d41a724b14683..0bd894909f09c8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -738,7 +738,7 @@ public static explicit operator Half(float value) const uint SingleBiasedExponentMask = float.BiasedExponentMask; // Exponent displacement #2 const uint Exponent13 = 0x0680_0000u; - // The value above Half.MaxValue + // The maximum infinitely precise value that will round down to MaxValue const float HalfAboveMaxValue = 65520.0f; // Mask for exponent bits in Half const uint ExponentMask = BiasedExponentMask; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 89a11b9426fe34..037044177754fe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -1604,8 +1604,8 @@ private static bool TryConvertFromSaturating(TOther value, out Int128 re else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x7F00)) ? MaxValue : - (actualValue <= BitConverter.UInt16BitsToBFloat16(0xFF00)) ? MinValue : (Int128)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x7F00)) /* (BFloat16)MaxValue */ ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xFF00)) /* (BFloat16)MinValue */ ? MinValue : (Int128)actualValue; return true; } else if (typeof(TOther) == typeof(short)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index cb128c7f2875ff..a099b449931601 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -974,15 +974,15 @@ private static bool TryConvertFromSaturating(TOther value, out short res else if (typeof(TOther) == typeof(Half)) { Half actualValue = (Half)(object)value; - result = (actualValue >= BitConverter.UInt16BitsToHalf(0x7800)) ? MaxValue : - (actualValue <= BitConverter.UInt16BitsToHalf(0xF800)) ? MinValue : (short)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToHalf(0x7800)) /* (Half)MaxValue */ ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToHalf(0xF800)) /* (Half)MinValue */ ? MinValue : (short)actualValue; return true; } else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4700)) ? MaxValue : - (actualValue <= BitConverter.UInt16BitsToBFloat16(0xB700)) ? MinValue : (short)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4700)) /* (BFloat16)MaxValue */ ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xB700)) /* (BFloat16)MinValue */ ? MinValue : (short)actualValue; return true; } else if (typeof(TOther) == typeof(int)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index d5caff910d55e2..bb5eda85aec3f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -1022,8 +1022,8 @@ private static bool TryConvertFromSaturating(TOther value, out int resul else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4F00)) ? MaxValue : - (actualValue <= BitConverter.UInt16BitsToBFloat16(0xBF00)) ? MinValue : (int)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x4F00)) /* (BFloat16)MaxValue */ ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xBF00)) /* (BFloat16)MinValue */ ? MinValue : (int)actualValue; return true; } else if (typeof(TOther) == typeof(short)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index 9bfcfe76fa4b1a..02b4c391a4f449 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -1019,8 +1019,8 @@ private static bool TryConvertFromSaturating(TOther value, out long resu else if (typeof(TOther) == typeof(BFloat16)) { BFloat16 actualValue = (BFloat16)(object)value; - result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x5F00)) ? MaxValue : - (actualValue <= BitConverter.UInt16BitsToBFloat16(0xCF00)) ? MinValue : (long)actualValue; + result = (actualValue >= BitConverter.UInt16BitsToBFloat16(0x5F00)) /* (BFloat16)MaxValue */ ? MaxValue : + (actualValue <= BitConverter.UInt16BitsToBFloat16(0xCF00)) /* (BFloat16)MinValue */ ? MinValue : (long)actualValue; return true; } else if (typeof(TOther) == typeof(short)) 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 3466fd09189a2d..816956938e5486 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs @@ -467,7 +467,7 @@ public static explicit operator BFloat16(double value) const ulong SingleBiasedExponentMask = double.BiasedExponentMask; // Exponent displacement #2 const ulong Exponent45 = 0x02D0_0000_0000_0000u; - // The value above BFloat16.MaxValue + // The maximum infinitely precise value that will round down to MaxValue const double BFloat16AboveMaxValue = 3.39617752923046E+38; // Mask for exponent bits in BFloat16 const ulong ExponentMask = BiasedExponentMask;