From 589afe066a57bd64c54ace0b12a2dcb40858d45f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 18 Feb 2024 22:56:42 +0800 Subject: [PATCH 01/54] 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 a73e8247a58e7..adb9620e6f49f 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 0000000000000..c3c14085b2a4f --- /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/54] 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 c3c14085b2a4f..9a136cdc4c7e6 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/54] 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 9a136cdc4c7e6..7cbc88c1b6e81 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/54] 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 b6d8fd00aa404..f9594228b08ce 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 7cbc88c1b6e81..58991935bedeb 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/54] 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 58991935bedeb..0a8a8062598a5 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/54] 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 0a8a8062598a5..a73a5b1432037 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/54] 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 a73a5b1432037..e31984820e961 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/54] 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 53bba2a3f3497..b68a5d8a64638 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/54] 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 6bcf41fe129bd..29cc2c8786332 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 0000000000000..ff55b0a951d42 --- /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/54] 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 ff55b0a951d42..2e83e73ac8bc3 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/54] 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 e31984820e961..368c5232be80d 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/54] 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 2e83e73ac8bc3..53eda2a785cc6 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/54] 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 53eda2a785cc6..1c4811807134d 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/54] 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 368c5232be80d..ecbaea141af4d 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/54] 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 ecbaea141af4d..8b28e2c9145d1 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/54] 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 8b28e2c9145d1..1d7db26fb3a84 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/54] 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 adc7df07932f7..eceabbe016ec7 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 1d7db26fb3a84..e5c4825a76f45 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/54] 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 e5c4825a76f45..4f643b656a2da 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/54] 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 4f643b656a2da..0950f6fa46630 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/54] 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 0950f6fa46630..6566fa03c3f25 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/54] 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 71d73546bc136..670fd1f865cbd 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 eceabbe016ec7..95896ad046902 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 6566fa03c3f25..25140a8bdfe82 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 9cc7c6b56c0ad..e69c8b02daae0 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/54] 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 952733c9268df..7cc35e9247e4a 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/54] 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 25140a8bdfe82..4281d5fac46fd 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/54] 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 5b4fc7a7564e8..9df0e5c4771ba 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 7cc35e9247e4a..34b4c8926437b 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/54] 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 670fd1f865cbd..71d73546bc136 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 34b4c8926437b..e0e22220d2194 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 e69c8b02daae0..9cc7c6b56c0ad 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/54] 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 95896ad046902..3130b7b94a89e 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 e0e22220d2194..387f03ab750fc 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 4281d5fac46fd..caea4678a0bc7 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 9cc7c6b56c0ad..108c6b1d60b0f 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/54] 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 caea4678a0bc7..a6d87f8fc06db 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/54] 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 a6d87f8fc06db..8702d8682f241 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/54] 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 8702d8682f241..281324cad0569 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/54] 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 9df0e5c4771ba..5b4fc7a7564e8 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 adb9620e6f49f..88bcc6089c6a0 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 4a746b38cc2c3..8858aa478f480 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 0000000000000..6088571b7994d --- /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/54] 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 88bcc6089c6a0..db7584876a2d5 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 281324cad0569..db36836c936d5 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/54] 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 268bd53695e7d..c910c0bcff874 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 ad75d88cbda7c..48b0be3be8729 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/54] 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 4a746b38cc2c3..b4e01cac10a97 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/54] 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 10fbfcdbee547..2a50766a9ff43 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/54] 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 71d73546bc136..442d5b303efbf 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 adc7df07932f7..73ca82c0c934d 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 852b979492c2d..263f60ad0ba10 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 9cc7c6b56c0ad..87606cbd61424 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/54] 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 48b0be3be8729..e378d85921b81 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/54] 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 442d5b303efbf..9a69c2d6e448b 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 73ca82c0c934d..fcac21f18eb90 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 c910c0bcff874..49148306fff0f 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 2a50766a9ff43..038fdb23947dd 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 e378d85921b81..e1b743f142dde 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 b4e01cac10a97..e4a25b9b5939c 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 87606cbd61424..2ce82e0776467 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/54] 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 d0902cffef527..e5caa915534a2 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 db36836c936d5..3c329a6478fb9 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/54] 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 8cb77cbba7bfb..5a2f71d175a4c 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 3c329a6478fb9..a657ff553f94c 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 6088571b7994d..0000000000000 --- 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/54] 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 333d12a916dff..81cf5c7b12371 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/54] 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 1c4811807134d..3281fded0a4d1 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/54] 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 3281fded0a4d1..b63d12ba38906 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/54] 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 b63d12ba38906..f7e92a0144699 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/54] 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 a657ff553f94c..58d20219d523f 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 f7e92a0144699..7ca93c71b8b31 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/54] 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 7ca93c71b8b31..7d71d9f5c0638 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/54] 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 7d71d9f5c0638..df086a55f91f2 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/54] 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 df086a55f91f2..86665c0f9603d 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/54] 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 86665c0f9603d..dd836904d5c27 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/54] 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 dd836904d5c27..d633b285e0811 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/54] 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 21e21031ba0c9..85258d052b0c3 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 58d20219d523f..2b4b704528121 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/54] 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 cba358e484acc..e3733a53f2f9d 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 d633b285e0811..50f999e479c84 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/54] 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 50f999e479c84..af764c7c887ba 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/54] 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 2b4b704528121..04f5412fcbc52 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/54] 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 74e9b62b07d27..e4a25b9b5939c 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;