From 0a8edce51d7a415abb09313b105b4a2dcf1c9f1a Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Aug 2026 18:23:30 -0700 Subject: [PATCH 1/4] Remove the Number static constructor Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/System/Number.Formatting.Common.cs | 83 +- .../Number.DecimalIeee754.DiyFp128Exp.cs | 108 +-- .../Number.DecimalIeee754.DiyFp128Hyper.cs | 56 +- .../Number.DecimalIeee754.DiyFp128InvTrig.cs | 146 ++-- .../Number.DecimalIeee754.DiyFp128Log.cs | 40 +- .../Number.DecimalIeee754.DiyFp128PiTrig.cs | 23 +- .../Number.DecimalIeee754.DiyFp128Pow.cs | 90 +- .../Number.DecimalIeee754.DiyFp128Sqrt.cs | 794 ++++++++++++------ .../Number.DecimalIeee754.DiyFp128Trig.cs | 110 +-- .../Number.DecimalIeee754.Transcendental.cs | 32 +- .../src/System/Number.Formatting.cs | 63 +- 11 files changed, 911 insertions(+), 634 deletions(-) diff --git a/src/libraries/Common/src/System/Number.Formatting.Common.cs b/src/libraries/Common/src/System/Number.Formatting.Common.cs index e24c971efc1c93..8a5a9397adcff8 100644 --- a/src/libraries/Common/src/System/Number.Formatting.Common.cs +++ b/src/libraries/Common/src/System/Number.Formatting.Common.cs @@ -19,38 +19,47 @@ internal static partial class Number private const int MaxUInt32DecDigits = 10; private const string PosNumberFormat = "#"; - private static readonly string[] s_posCurrencyFormats = - [ - "$#", "#$", "$ #", "# $" - ]; - - private static readonly string[] s_negCurrencyFormats = - [ - "($#)", "-$#", "$-#", "$#-", - "(#$)", "-#$", "#-$", "#$-", - "-# $", "-$ #", "# $-", "$ #-", - "$ -#", "#- $", "($ #)", "(# $)", - "$- #" - ]; - - private static readonly string[] s_posPercentFormats = - [ - "# %", "#%", "%#", "% #" - ]; - - private static readonly string[] s_negPercentFormats = - [ - "-# %", "-#%", "-%#", - "%-#", "%#-", - "#-%", "#%-", - "-% #", "# %-", "% #-", - "% -#", "#- %" - ]; - - private static readonly string[] s_negNumberFormats = - [ - "(#)", "-#", "- #", "#-", "# -", - ]; + private static class CurrencyFormats + { + internal static readonly string[] Positive = + [ + "$#", "#$", "$ #", "# $" + ]; + + internal static readonly string[] Negative = + [ + "($#)", "-$#", "$-#", "$#-", + "(#$)", "-#$", "#-$", "#$-", + "-# $", "-$ #", "# $-", "$ #-", + "$ -#", "#- $", "($ #)", "(# $)", + "$- #" + ]; + } + + private static class PercentFormats + { + internal static readonly string[] Positive = + [ + "# %", "#%", "%#", "% #" + ]; + + internal static readonly string[] Negative = + [ + "-# %", "-#%", "-%#", + "%-#", "%#-", + "#-%", "#%-", + "-% #", "# %-", "% #-", + "% -#", "#- %" + ]; + } + + private static class NumberFormats + { + internal static readonly string[] Negative = + [ + "(#)", "-#", "- #", "#-", "# -", + ]; + } internal static char ParseFormatSpecifier(ReadOnlySpan format, out int digits) { @@ -724,8 +733,8 @@ private static unsafe void FormatCurrency(ref ValueListBuilder vlb Debug.Assert(sizeof(TChar) is sizeof(char) or sizeof(byte)); string fmt = number.IsNegative ? - s_negCurrencyFormats[info.CurrencyNegativePattern] : - s_posCurrencyFormats[info.CurrencyPositivePattern]; + CurrencyFormats.Negative[info.CurrencyNegativePattern] : + CurrencyFormats.Positive[info.CurrencyPositivePattern]; foreach (char ch in fmt) { @@ -894,7 +903,7 @@ private static unsafe void FormatNumber(ref ValueListBuilder vlb, Debug.Assert(sizeof(TChar) is sizeof(char) or sizeof(byte)); string fmt = number.IsNegative ? - s_negNumberFormats[info.NumberNegativePattern] : + NumberFormats.Negative[info.NumberNegativePattern] : PosNumberFormat; foreach (char ch in fmt) @@ -1021,8 +1030,8 @@ private static unsafe void FormatPercent(ref ValueListBuilder vlb, Debug.Assert(sizeof(TChar) is sizeof(char) or sizeof(byte)); string fmt = number.IsNegative ? - s_negPercentFormats[info.PercentNegativePattern] : - s_posPercentFormats[info.PercentPositivePattern]; + PercentFormats.Negative[info.PercentNegativePattern] : + PercentFormats.Positive[info.PercentPositivePattern]; foreach (char ch in fmt) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Exp.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Exp.cs index 41f0ae8d7c136f..4ff9eb8410ee11 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Exp.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Exp.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Numerics; +using System.Runtime.InteropServices; namespace System; @@ -30,6 +31,13 @@ private readonly struct DiyFp128FixedCoefficient(ulong lo, ulong hi) internal readonly ulong High = hi; } + private static ReadOnlySpan DiyFp128FixedCoefficients(ReadOnlySpan coefficients) + { + Debug.Assert((coefficients.Length & 1) == 0); + + return MemoryMarshal.Cast(coefficients); + } + // High 64 bits of a 64x64 product (Intel's UMULH). private static ulong DiyFp128MultiplyHigh(ulong a, ulong b) => Math.BigMul(a, b, out _); @@ -44,32 +52,32 @@ private readonly struct DiyFp128FixedCoefficient(ulong lo, ulong hi) // ln2_lo = ln2 - ln2_hi, as an unpacked value. private static DiyFp128 ExpLn2Low => new DiyFp128(UxSignBit, -66, 0xD871319FF0342542, 0xFC32F366359D2749); - private static readonly DiyFp128FixedCoefficient[] ExpCoefficients = + private static ReadOnlySpan ExpCoefficients => DiyFp128FixedCoefficients( [ - new(0x0219C7290393A749, 0x0000000000000000), - new(0x2E468FC7B47B630C, 0x0000000000000000), - new(0xCA85AD657F5C80BD, 0x0000000000000003), - new(0xD268B2CB49B64EAE, 0x000000000000004B), - new(0x9E18D9E0EB90C661, 0x00000000000005A0), - new(0x1DC178468FE824F4, 0x000000000000654B), - new(0xF9CCF1842631A1A2, 0x000000000006B9FC), - new(0x9CCECE542F079EEB, 0x00000000006B9FCF), - new(0x301F26EFF3934011, 0x00000000064E5D2A), - new(0xA1B4271D14562C06, 0x000000005849184E), - new(0x3625ED5697A1173A, 0x000000047BB63BFE), - new(0x89C71FC24062E495, 0x00000035CC8ACFEA), - new(0xEB8E5DDFF9B4C26E, 0x0000024FC9F6EF13), - new(0x338FAAC2198CD02D, 0x0000171DE3A556C7), - new(0xD00D00D00E2C1D71, 0x0000D00D00D00D00), - new(0x8068068066CFB7B5, 0x0006806806806806), - new(0x82D82D82D829D3B1, 0x002D82D82D82D82D), - new(0x111111111113746F, 0x0111111111111111), - new(0x5555555555555AA3, 0x0555555555555555), - new(0x5555555555555380, 0x1555555555555555), - new(0xFFFFFFFFFFFFFFFE, 0x3FFFFFFFFFFFFFFF), - new(0x0000000000000000, 0x8000000000000000), - new(0x0000000000000000, 0x8000000000000000), - ]; + 0x0219C7290393A749, 0x0000000000000000, + 0x2E468FC7B47B630C, 0x0000000000000000, + 0xCA85AD657F5C80BD, 0x0000000000000003, + 0xD268B2CB49B64EAE, 0x000000000000004B, + 0x9E18D9E0EB90C661, 0x00000000000005A0, + 0x1DC178468FE824F4, 0x000000000000654B, + 0xF9CCF1842631A1A2, 0x000000000006B9FC, + 0x9CCECE542F079EEB, 0x00000000006B9FCF, + 0x301F26EFF3934011, 0x00000000064E5D2A, + 0xA1B4271D14562C06, 0x000000005849184E, + 0x3625ED5697A1173A, 0x000000047BB63BFE, + 0x89C71FC24062E495, 0x00000035CC8ACFEA, + 0xEB8E5DDFF9B4C26E, 0x0000024FC9F6EF13, + 0x338FAAC2198CD02D, 0x0000171DE3A556C7, + 0xD00D00D00E2C1D71, 0x0000D00D00D00D00, + 0x8068068066CFB7B5, 0x0006806806806806, + 0x82D82D82D829D3B1, 0x002D82D82D82D82D, + 0x111111111113746F, 0x0111111111111111, + 0x5555555555555AA3, 0x0555555555555555, + 0x5555555555555380, 0x1555555555555555, + 0xFFFFFFFFFFFFFFFE, 0x3FFFFFFFFFFFFFFF, + 0x0000000000000000, 0x8000000000000000, + 0x0000000000000000, 0x8000000000000000, + ]); // ---- exp10 (base 10) constant table (dpml_exp_x.h) ---- // The exp10 polynomial approximates 10^t directly, so the reduction subtracts scale*log10(2) and the @@ -84,32 +92,32 @@ private readonly struct DiyFp128FixedCoefficient(ulong lo, ulong hi) // log10(2)_lo, as an unpacked value. private static DiyFp128 Exp10Ln2Low => new DiyFp128(UxSignBit, -66, 0xE0ED4CA7E906DD0F, 0xB2A59E75785C196C); - private static readonly DiyFp128FixedCoefficient[] Exp10Coefficients = + private static ReadOnlySpan Exp10Coefficients => DiyFp128FixedCoefficients( [ - new(0xAA326D76E12A5F3D, 0x000000000005D18C), - new(0xBB46D2D76A135C14, 0x000000000037BD19), - new(0x2188762E74D6A84B, 0x0000000001FBA820), - new(0x10A5EEBAE5E25723, 0x0000000011396F18), - new(0xB3FCD05A246EA126, 0x000000008E20E630), - new(0x11F8F23A20DD37FD, 0x00000004570FB29C), - new(0x167B5D1D64BF3431, 0x000000200AF8FBFF), - new(0xB407C79F854435F8, 0x000000DEA8177BC6), - new(0xAEF77A1B0616E83B, 0x000005AA7A612E29), - new(0x119B2348D3C5FBA9, 0x0000227315A5882E), - new(0x20D8613A1E07D507, 0x0000C27F096FC05F), - new(0x7F472BC73DD8F81C, 0x0003F59FABB213AC), - new(0x674C9F4591A76481, 0x0012EA52B2D182AF), - new(0xC9822F93893BB4F4, 0x005225F11764F507), - new(0xF088AE28F92F4908, 0x014116B05FDAA5CD), - new(0xC160BBA8AA4224B1, 0x045B937F0CCEA1AC), - new(0xD9F3DCD36EBEE310, 0x0D3F6B8423E45AEB), - new(0x5C6542259124B3BC, 0x22853FFA3A9AEC44), - new(0xEA51F65ED9F90D3B, 0x4AF5D827F6631131), - new(0x6A4F9D820D46BA57, 0x82382C8EF1652304), - new(0x80A99CE52D65A6EC, 0xA9A92639E753443A), - new(0xEA56D62B82D30A2C, 0x935D8DDDAAA8AC16), - new(0x0000000000000000, 0x4000000000000000), - ]; + 0xAA326D76E12A5F3D, 0x000000000005D18C, + 0xBB46D2D76A135C14, 0x000000000037BD19, + 0x2188762E74D6A84B, 0x0000000001FBA820, + 0x10A5EEBAE5E25723, 0x0000000011396F18, + 0xB3FCD05A246EA126, 0x000000008E20E630, + 0x11F8F23A20DD37FD, 0x00000004570FB29C, + 0x167B5D1D64BF3431, 0x000000200AF8FBFF, + 0xB407C79F854435F8, 0x000000DEA8177BC6, + 0xAEF77A1B0616E83B, 0x000005AA7A612E29, + 0x119B2348D3C5FBA9, 0x0000227315A5882E, + 0x20D8613A1E07D507, 0x0000C27F096FC05F, + 0x7F472BC73DD8F81C, 0x0003F59FABB213AC, + 0x674C9F4591A76481, 0x0012EA52B2D182AF, + 0xC9822F93893BB4F4, 0x005225F11764F507, + 0xF088AE28F92F4908, 0x014116B05FDAA5CD, + 0xC160BBA8AA4224B1, 0x045B937F0CCEA1AC, + 0xD9F3DCD36EBEE310, 0x0D3F6B8423E45AEB, + 0x5C6542259124B3BC, 0x22853FFA3A9AEC44, + 0xEA51F65ED9F90D3B, 0x4AF5D827F6631131, + 0x6A4F9D820D46BA57, 0x82382C8EF1652304, + 0x80A99CE52D65A6EC, 0xA9A92639E753443A, + 0xEA56D62B82D30A2C, 0x935D8DDDAAA8AC16, + 0x0000000000000000, 0x4000000000000000, + ]); // 1.0 as an unpacked value (Intel's UX_ONE). private static DiyFp128 DiyFp128One => new DiyFp128(0, 1, 0x8000000000000000, 0); diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Hyper.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Hyper.cs index a9cd40af4f5348..fca5f4215fdb96 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Hyper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Hyper.cs @@ -40,38 +40,38 @@ internal static partial class Number private const int HyperSinhCoshTrailingExponent = 1; // Fixed point coefficients for sinh/cosh evaluation (dpml_exp_x.h, SINHCOSH_COEF_ARRAY numerator). - private static readonly DiyFp128FixedCoefficient[] HyperSinhCoefficients = + private static ReadOnlySpan HyperSinhCoefficients => DiyFp128FixedCoefficients( [ - new(0x0000000000000000, 0x0000000000000000), - new(0x2E4690EB84E45693, 0x0000000000000000), - new(0xD268B21C12FFD219, 0x000000000000004B), - new(0x1DC1787345BBF199, 0x000000000000654B), - new(0x9CCECE4DDE16535A, 0x00000000006B9FCF), - new(0xA1B4271D9E5E08B2, 0x000000005849184E), - new(0x89C71FC2391817AA, 0x00000035CC8ACFEA), - new(0x338FAAC219C8D92F, 0x0000171DE3A556C7), - new(0x8068068066CE9BD9, 0x0006806806806806), - new(0x1111111111137719, 0x0111111111111111), - new(0x555555555555537E, 0x1555555555555555), - new(0x0000000000000000, 0x8000000000000000), - ]; + 0x0000000000000000, 0x0000000000000000, + 0x2E4690EB84E45693, 0x0000000000000000, + 0xD268B21C12FFD219, 0x000000000000004B, + 0x1DC1787345BBF199, 0x000000000000654B, + 0x9CCECE4DDE16535A, 0x00000000006B9FCF, + 0xA1B4271D9E5E08B2, 0x000000005849184E, + 0x89C71FC2391817AA, 0x00000035CC8ACFEA, + 0x338FAAC219C8D92F, 0x0000171DE3A556C7, + 0x8068068066CE9BD9, 0x0006806806806806, + 0x1111111111137719, 0x0111111111111111, + 0x555555555555537E, 0x1555555555555555, + 0x0000000000000000, 0x8000000000000000, + ]); // Fixed point coefficients for sinh/cosh evaluation (dpml_exp_x.h, SINHCOSH_COEF_ARRAY denominator). - private static readonly DiyFp128FixedCoefficient[] HyperCoshCoefficients = + private static ReadOnlySpan HyperCoshCoefficients => DiyFp128FixedCoefficients( [ - new(0x021A7ACFAB2871A0, 0x0000000000000000), - new(0xCA853BED72A41925, 0x0000000000000003), - new(0x9E18F89AF7B71018, 0x00000000000005A0), - new(0xF9CCECDB5C564D82, 0x000000000006B9FC), - new(0x301F275EEE64C398, 0x00000000064E5D2A), - new(0x3625ED50108A94FE, 0x000000047BB63BFE), - new(0xEB8E5DE0376E0580, 0x0000024FC9F6EF13), - new(0xD00D00D00CCC1E48, 0x0000D00D00D00D00), - new(0x82D82D82D82E2A61, 0x002D82D82D82D82D), - new(0x5555555555555442, 0x0555555555555555), - new(0x0000000000000001, 0x4000000000000000), - new(0x0000000000000000, 0x8000000000000000), - ]; + 0x021A7ACFAB2871A0, 0x0000000000000000, + 0xCA853BED72A41925, 0x0000000000000003, + 0x9E18F89AF7B71018, 0x00000000000005A0, + 0xF9CCECDB5C564D82, 0x000000000006B9FC, + 0x301F275EEE64C398, 0x00000000064E5D2A, + 0x3625ED50108A94FE, 0x000000047BB63BFE, + 0xEB8E5DE0376E0580, 0x0000024FC9F6EF13, + 0xD00D00D00CCC1E48, 0x0000D00D00D00D00, + 0x82D82D82D82E2A61, 0x002D82D82D82D82D, + 0x5555555555555442, 0x0555555555555555, + 0x0000000000000001, 0x4000000000000000, + 0x0000000000000000, 0x8000000000000000, + ]); // Intel's UX_HYPERBOLIC: argument reduction x = I*ln2 + z (|z| < ln2/2) then either a direct // polynomial (|x| < ln2/2, to avoid loss of significance) or exp(z)/exp(-z) reconstruction. diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128InvTrig.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128InvTrig.cs index 2977a6e4ad45e1..919290fada96cb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128InvTrig.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128InvTrig.cs @@ -33,78 +33,84 @@ internal static partial class Number // INV_TRIG_CONS_BASE (dpml_inv_trig_x.h): 0, pi/4, pi/2, 3pi/4, pi. Intel spaces these entries // 24 bytes apart, so the packed byte offset divided by 24 selects the constant. - private static readonly DiyFp128[] InvTrigConstants = - [ - new DiyFp128(0, UxZeroExponent, 0, 0), // 0 - new DiyFp128(0, 0, 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1), // pi/4 - new DiyFp128(0, 1, 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1), // pi/2 - new DiyFp128(0, 2, 0x96CBE3F9990E91A7, 0x9394C9E8A0A5159C), // 3pi/4 - new DiyFp128(0, 2, 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1), // pi - ]; - - private static readonly DiyFp128FixedCoefficient[] InvTrigAtanNumeratorCoefficients = + private static DiyFp128 GetInvTrigConstant(int index) + { + ReadOnlySpan exponents = [UxZeroExponent, 0, 1, 2, 2]; + ReadOnlySpan significands = + [ + 0, 0, + 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1, + 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1, + 0x96CBE3F9990E91A7, 0x9394C9E8A0A5159C, + 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1, + ]; + + return new DiyFp128(0, exponents[index], significands[index * 2], significands[(index * 2) + 1]); + } + + private static ReadOnlySpan InvTrigAtanNumeratorCoefficients => DiyFp128FixedCoefficients( [ - new(0x0000000000000000, 0x0000000000000000), - new(0x9B21DB1817B033DE, 0x00000000036A28B8), - new(0x7AF48D0CBBB9E258, 0x00000004A9D8AEAC), - new(0x710B595CB5F5477A, 0x000001D601B80364), - new(0x82FF5AD5BDC83502, 0x00005360DB2203CD), - new(0xA46EA356B3ACE8E0, 0x000803A15271C15D), - new(0x511728BC47FD897A, 0x00752012D71DF9B4), - new(0xB0EEBD1D38E6CCD7, 0x04261AAD0C0E0AEF), - new(0x715215EE2223A644, 0x178D58E7069E5E06), - new(0x1A5B5968DAA31B09, 0x515E68B909775969), - new(0xA67DE44D68DB7EF7, 0x9C53EDB8B65E0E57), - new(0x0000000000000000, 0x8000000000000000), - ]; - - private static readonly DiyFp128FixedCoefficient[] InvTrigAtanDenominatorCoefficients = + 0x0000000000000000, 0x0000000000000000, + 0x9B21DB1817B033DE, 0x00000000036A28B8, + 0x7AF48D0CBBB9E258, 0x00000004A9D8AEAC, + 0x710B595CB5F5477A, 0x000001D601B80364, + 0x82FF5AD5BDC83502, 0x00005360DB2203CD, + 0xA46EA356B3ACE8E0, 0x000803A15271C15D, + 0x511728BC47FD897A, 0x00752012D71DF9B4, + 0xB0EEBD1D38E6CCD7, 0x04261AAD0C0E0AEF, + 0x715215EE2223A644, 0x178D58E7069E5E06, + 0x1A5B5968DAA31B09, 0x515E68B909775969, + 0xA67DE44D68DB7EF7, 0x9C53EDB8B65E0E57, + 0x0000000000000000, 0x8000000000000000, + ]); + + private static ReadOnlySpan InvTrigAtanDenominatorCoefficients => DiyFp128FixedCoefficients( [ - new(0x753B0A86A07A791A, 0x0000000000060285), - new(0xB62B5E42F41004BB, 0x000000001A6A8474), - new(0x6AF09BC24E1E2DAD, 0x00000012CF340CF3), - new(0x49426EE8106AF1A7, 0x00000523BCE40E29), - new(0xD77AD56C6CCAE258, 0x0000B5F6388D7935), - new(0x95AA5864A5D93FD4, 0x000E856C505D9AB5), - new(0xF9512F8649A8F559, 0x00B744F2C988C73A), - new(0x247CE9CC4DDD2493, 0x05C2135495031B41), - new(0xC6922892F40A72FC, 0x1D8EB88DDE3BC4F4), - new(0x0785210E97FF604A, 0x5DAF5BD2629E79E5), - new(0x51288EF813862999, 0xA6FE98636108B902), - new(0x0000000000000000, 0x8000000000000000), - ]; - - private static readonly DiyFp128FixedCoefficient[] InvTrigAsinNumeratorCoefficients = + 0x753B0A86A07A791A, 0x0000000000060285, + 0xB62B5E42F41004BB, 0x000000001A6A8474, + 0x6AF09BC24E1E2DAD, 0x00000012CF340CF3, + 0x49426EE8106AF1A7, 0x00000523BCE40E29, + 0xD77AD56C6CCAE258, 0x0000B5F6388D7935, + 0x95AA5864A5D93FD4, 0x000E856C505D9AB5, + 0xF9512F8649A8F559, 0x00B744F2C988C73A, + 0x247CE9CC4DDD2493, 0x05C2135495031B41, + 0xC6922892F40A72FC, 0x1D8EB88DDE3BC4F4, + 0x0785210E97FF604A, 0x5DAF5BD2629E79E5, + 0x51288EF813862999, 0xA6FE98636108B902, + 0x0000000000000000, 0x8000000000000000, + ]); + + private static ReadOnlySpan InvTrigAsinNumeratorCoefficients => DiyFp128FixedCoefficients( [ - new(0xBC844BD3285A9ADB, 0x000000000018A298), - new(0x24543A40FF2FC62E, 0x000000004B712F53), - new(0x2553512C4DB90D47, 0x0000002B42B22A11), - new(0x4670C8AC9560DE1D, 0x00000A0239855097), - new(0x022DDA0E53EF4CB8, 0x00013575BD533BC9), - new(0xAFC38A68688E8800, 0x00160D59ECE50095), - new(0x6123E0EEA5F3E527, 0x00FCC7EE91E17495), - new(0xFA699043FFD8CC09, 0x074FACFD5647265E), - new(0x7DD602B0DF4A1E6D, 0x22EDBCFCE68005C2), - new(0xA938FA69D688D50A, 0x67F826ED129B3E51), - new(0xFF93B5CB3865C5F2, 0xAF5C9B73F163DD08), - new(0x0000000000000000, 0x8000000000000000), - ]; - - private static readonly DiyFp128FixedCoefficient[] InvTrigAsinDenominatorCoefficients = + 0xBC844BD3285A9ADB, 0x000000000018A298, + 0x24543A40FF2FC62E, 0x000000004B712F53, + 0x2553512C4DB90D47, 0x0000002B42B22A11, + 0x4670C8AC9560DE1D, 0x00000A0239855097, + 0x022DDA0E53EF4CB8, 0x00013575BD533BC9, + 0xAFC38A68688E8800, 0x00160D59ECE50095, + 0x6123E0EEA5F3E527, 0x00FCC7EE91E17495, + 0xFA699043FFD8CC09, 0x074FACFD5647265E, + 0x7DD602B0DF4A1E6D, 0x22EDBCFCE68005C2, + 0xA938FA69D688D50A, 0x67F826ED129B3E51, + 0xFF93B5CB3865C5F2, 0xAF5C9B73F163DD08, + 0x0000000000000000, 0x8000000000000000, + ]); + + private static ReadOnlySpan InvTrigAsinDenominatorCoefficients => DiyFp128FixedCoefficients( [ - new(0xEDE27D48152467C1, 0x0000000000882734), - new(0x1D75E618BE470341, 0x00000000CA5275D0), - new(0x001C0AB3C7D6F6E2, 0x000000559CC8243B), - new(0x36449091EA1AF30D, 0x000010830F45B29D), - new(0x9692608B4850F9DD, 0x0001C28A726A35F0), - new(0x755313B950B194C6, 0x001D43C1AA0112DE), - new(0x555FF65FD5BD1184, 0x013820000042983F), - new(0xA448034F044AD977, 0x0884C1099A59728A), - new(0x0743CFA35361E105, 0x26CAAD31C3EC7BEC), - new(0x5329169C42D6FDEB, 0x6EE5F75BDBF406D1), - new(0x54E90B208DBB1B38, 0xB4B1F0C946B9325E), - new(0x0000000000000000, 0x8000000000000000), - ]; + 0xEDE27D48152467C1, 0x0000000000882734, + 0x1D75E618BE470341, 0x00000000CA5275D0, + 0x001C0AB3C7D6F6E2, 0x000000559CC8243B, + 0x36449091EA1AF30D, 0x000010830F45B29D, + 0x9692608B4850F9DD, 0x0001C28A726A35F0, + 0x755313B950B194C6, 0x001D43C1AA0112DE, + 0x555FF65FD5BD1184, 0x013820000042983F, + 0xA448034F044AD977, 0x0884C1099A59728A, + 0x0743CFA35361E105, 0x26CAAD31C3EC7BEC, + 0x5329169C42D6FDEB, 0x6EE5F75BDBF406D1, + 0x54E90B208DBB1B38, 0xB4B1F0C946B9325E, + 0x0000000000000000, 0x8000000000000000, + ]); // UX_ATAN2. When haveX is false this is the single-argument atan (Intel's null x pointer, aux_x = 1). private static DiyFp128 DiyFp128Atan2(DiyFp128 y, DiyFp128 x, bool haveX) @@ -190,7 +196,7 @@ private static DiyFp128 DiyFp128Atan2(DiyFp128 y, DiyFp128 x, bool haveX) int constantOffset = (int)((map >> index) & (0xFL << 3)); DiyFp128Normalize(ref value); DiyFp128 sum = default; - DiyFp128AddSub(InvTrigConstants[constantOffset / 24], value, UxAdd | UxNoNormalization, new Span(ref sum)); + DiyFp128AddSub(GetInvTrigConstant(constantOffset / 24), value, UxAdd | UxNoNormalization, new Span(ref sum)); value = sum; } @@ -242,7 +248,7 @@ private static DiyFp128 DiyFp128AsinAcos(DiyFp128 arg, bool isAcos) value._exponent += exponentIncrement; DiyFp128 sum = default; - DiyFp128AddSub(InvTrigConstants[(mapInfo & 0xF0) / 24], value, UxAdd | UxNoNormalization, new Span(ref sum)); + DiyFp128AddSub(GetInvTrigConstant((mapInfo & 0xF0) / 24), value, UxAdd | UxNoNormalization, new Span(ref sum)); value = sum; value._sign = ((mapInfo & 4) != 0) ? UxSignBit : 0; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Log.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Log.cs index 3a714f0679f60c..5575894209cffe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Log.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Log.cs @@ -26,27 +26,27 @@ internal static partial class Number private const int Log2Degree = 17; private const int Log2TrailingExponent = 2; - private static readonly DiyFp128FixedCoefficient[] Log2Coefficients = + private static ReadOnlySpan Log2Coefficients => DiyFp128FixedCoefficients( [ - new(0x271EEE7D56DAC09B, 0x06CC4D0D2A1966CE), - new(0x1BA3468B6F81E43D, 0x056711399CAAC22D), - new(0xF7CA0B25A20F818F, 0x05F8B50232B2540A), - new(0x7ADFA93E3F28F8FE, 0x065DF4E9CB8D055C), - new(0xCE5C4EA3F7891D9D, 0x06D6E7804C87D854), - new(0xE820F58A9FEB8D1E, 0x0762F8145C44B19A), - new(0xE8C1F4C0F720BB2C, 0x080766BF41DAD530), - new(0x80535F751DF3812C, 0x08CB27637D59049F), - new(0x96E6A1D72C2AC1EB, 0x09B81E0FA68AC838), - new(0x8C3B0C947DF70971, 0x0ADCD64DBA1F8070), - new(0xA70095AA11D8754E, 0x0C4F9D8B4A67FF05), - new(0x64F2A61E05F3CEFE, 0x0E347AB4698BB00E), - new(0x572DC64D3936B199, 0x10C9A84994022D28), - new(0x6A80DDD58C4AC6FE, 0x1484B13D7C02A8F8), - new(0x645C921FA5C4559C, 0x1A61762A7ADED93F), - new(0x594E6629AE4A965A, 0x24EED8A1DF37FCF2), - new(0x3F82AA45785F1ACB, 0x3D8E13B87407FAE9), - new(0xBE87FED0691D3E89, 0xB8AA3B295C17F0BB), - ]; + 0x271EEE7D56DAC09B, 0x06CC4D0D2A1966CE, + 0x1BA3468B6F81E43D, 0x056711399CAAC22D, + 0xF7CA0B25A20F818F, 0x05F8B50232B2540A, + 0x7ADFA93E3F28F8FE, 0x065DF4E9CB8D055C, + 0xCE5C4EA3F7891D9D, 0x06D6E7804C87D854, + 0xE820F58A9FEB8D1E, 0x0762F8145C44B19A, + 0xE8C1F4C0F720BB2C, 0x080766BF41DAD530, + 0x80535F751DF3812C, 0x08CB27637D59049F, + 0x96E6A1D72C2AC1EB, 0x09B81E0FA68AC838, + 0x8C3B0C947DF70971, 0x0ADCD64DBA1F8070, + 0xA70095AA11D8754E, 0x0C4F9D8B4A67FF05, + 0x64F2A61E05F3CEFE, 0x0E347AB4698BB00E, + 0x572DC64D3936B199, 0x10C9A84994022D28, + 0x6A80DDD58C4AC6FE, 0x1484B13D7C02A8F8, + 0x645C921FA5C4559C, 0x1A61762A7ADED93F, + 0x594E6629AE4A965A, 0x24EED8A1DF37FCF2, + 0x3F82AA45785F1ACB, 0x3D8E13B87407FAE9, + 0xBE87FED0691D3E89, 0xB8AA3B295C17F0BB, + ]); // 1/sqrt(2) fraction MSD and the I_RECIP_SQRT_2 / I_SQRT_2 range constants (dpml_log_x.h). private const ulong LogOneOverSqrt2 = 0xB504F333F9DE6484; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128PiTrig.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128PiTrig.cs index 611bab71048c63..36ba2af64b8729 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128PiTrig.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128PiTrig.cs @@ -17,21 +17,20 @@ internal static partial class Number // below 2^113), so the pi-scaled reduction avoids the large-argument cancellation that motivates a // dedicated *Pi routine. The inverse variants are the radian result divided by pi. - private static readonly DiyFp128 UxQuarter = new DiyFp128(0, -1, UxMsb, 0); - private static readonly DiyFp128 UxHalf = new DiyFp128(0, 0, UxMsb, 0); - private static readonly DiyFp128 UxThreeQuarter = new DiyFp128(0, 0, 0xC000000000000000, 0); - private static readonly DiyFp128 UxOne = new DiyFp128(0, 1, UxMsb, 0); + private static DiyFp128 UxQuarter => new DiyFp128(0, -1, UxMsb, 0); + private static DiyFp128 UxHalf => new DiyFp128(0, 0, UxMsb, 0); + private static DiyFp128 UxThreeQuarter => new DiyFp128(0, 0, 0xC000000000000000, 0); + private static DiyFp128 UxOne => new DiyFp128(0, 1, UxMsb, 0); // 0, 1/4, 1/2, 3/4, 1 -- InvTrigConstants (0, pi/4, pi/2, 3pi/4, pi) divided by pi, for the exact // signed-zero/infinity quadrant results of the inverse *Pi variants. - private static readonly DiyFp128[] PiFractionConstants = new DiyFp128[] + private static DiyFp128 GetPiFractionConstant(int index) { - new DiyFp128(0, UxZeroExponent, 0, 0), // 0 - UxQuarter, // 1/4 - UxHalf, // 1/2 - UxThreeQuarter, // 3/4 - UxOne, // 1 - }; + ReadOnlySpan exponents = [UxZeroExponent, -1, 0, 0, 1]; + ReadOnlySpan significands = [0, UxMsb, UxMsb, 0xC000000000000000, UxMsb]; + + return new DiyFp128(0, exponents[index], significands[index], 0); + } private static bool DiyFp128IsZero(in DiyFp128 value) => (value._hi | value._lo) == 0; @@ -123,7 +122,7 @@ private static DiyFp128 DiyFp128Product(in DiyFp128 a, in DiyFp128 b) } // reduced (in [0, 1/4]) * pi -> a small angle in [0, pi/4]. - private static DiyFp128 DiyFp128TimesPi(in DiyFp128 reduced) => DiyFp128Product(reduced, InvTrigConstants[4]); + private static DiyFp128 DiyFp128TimesPi(in DiyFp128 reduced) => DiyFp128Product(reduced, GetInvTrigConstant(4)); private static DiyFp128 DiyFp128Difference(in DiyFp128 a, in DiyFp128 b) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Pow.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Pow.cs index 6c55ad82e42a05..8dc189059510d1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Pow.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Pow.cs @@ -34,58 +34,58 @@ internal static partial class Number private const int PowLog2Degree = 17; private const int PowLog2TrailingExponent = -4; - private static readonly DiyFp128FixedCoefficient[] PowLog2Coefficients = + private static ReadOnlySpan PowLog2Coefficients => DiyFp128FixedCoefficients( [ - new(0x846F0CDB9C3D3269, 0x0000000000000116), - new(0x0ED54DB254EC30FA, 0x000000000000072B), - new(0xC9FA6284DFE33A4B, 0x00000000000041BC), - new(0x99F674DEFC256DAA, 0x0000000000024519), - new(0xD7B95B07FBD9EAF3, 0x0000000000143436), - new(0xA13BA5817DBA85BC, 0x0000000000B4AAAB), - new(0xB7A943E619ECD788, 0x0000000006587797), - new(0x50FCDA140E2310DC, 0x00000000396C809C), - new(0x20DC94F8FC4954A4, 0x000000020B9CBE4A), - new(0x726AE205A00351A9, 0x00000012D2328609), - new(0x746DF3952E72008C, 0x000000AF210E17E1), - new(0x13599009FB43DEC4, 0x00000674700E7651), - new(0xD038E4EAF62944CF, 0x00003E01D7C437DB), - new(0xAEE9DF3B28865F8F, 0x00026219E54D1542), - new(0x5D557E397A082390, 0x0018402256FD52E7), - new(0x2932877A7AA6F59B, 0x0103950187A04E84), - new(0x47A3ED398C267804, 0x0BD19A0FD62F144C), - new(0x5079024EDD11FEE3, 0xA3FE9FFD641DA382), - ]; + 0x846F0CDB9C3D3269, 0x0000000000000116, + 0x0ED54DB254EC30FA, 0x000000000000072B, + 0xC9FA6284DFE33A4B, 0x00000000000041BC, + 0x99F674DEFC256DAA, 0x0000000000024519, + 0xD7B95B07FBD9EAF3, 0x0000000000143436, + 0xA13BA5817DBA85BC, 0x0000000000B4AAAB, + 0xB7A943E619ECD788, 0x0000000006587797, + 0x50FCDA140E2310DC, 0x00000000396C809C, + 0x20DC94F8FC4954A4, 0x000000020B9CBE4A, + 0x726AE205A00351A9, 0x00000012D2328609, + 0x746DF3952E72008C, 0x000000AF210E17E1, + 0x13599009FB43DEC4, 0x00000674700E7651, + 0xD038E4EAF62944CF, 0x00003E01D7C437DB, + 0xAEE9DF3B28865F8F, 0x00026219E54D1542, + 0x5D557E397A082390, 0x0018402256FD52E7, + 0x2932877A7AA6F59B, 0x0103950187A04E84, + 0x47A3ED398C267804, 0x0BD19A0FD62F144C, + 0x5079024EDD11FEE3, 0xA3FE9FFD641DA382, + ]); // 2^h fixed-point coefficients (dpml_pow_x.h), degree 22, trailing exponent 1. private const int Pow2Degree = 22; private const int Pow2TrailingExponent = 1; - private static readonly DiyFp128FixedCoefficient[] Pow2Coefficients = + private static ReadOnlySpan Pow2Coefficients => DiyFp128FixedCoefficients( [ - new(0x00002B4C151832AB, 0x0000000000000000), - new(0x000561D142DDB787, 0x0000000000000000), - new(0x00A2D67FD1C367C8, 0x0000000000000000), - new(0x125A7DA057182134, 0x0000000000000000), - new(0xF7176BC7BA507C6D, 0x0000000000000001), - new(0x088968A28FAC4875, 0x0000000000000033), - new(0xA26B9E85115B54C3, 0x00000000000004E3), - new(0xA10EC0E8D6AB2988, 0x00000000000070DB), - new(0x26AC3C533FCB6035, 0x0000000000098A4B), - new(0x8B3687CE8532C06F, 0x0000000000C0B0C9), - new(0x7E14C2F18E3A0B6B, 0x000000000E1DEB28), - new(0x8DD9260757EE4711, 0x00000000F465639A), - new(0xC764FB7ECC717D30, 0x0000000F267A8AC5), - new(0x3E1ED2538C4CB47E, 0x000000DA929E9CAF), - new(0x11FEC7FF3074CB1A, 0x00000B160111D2E4), - new(0x1A1AC54731EE7AD0, 0x00007FF2FF1622C3), - new(0xDBD2C2A261AA9A77, 0x00050C244BE1B1E1), - new(0x20E2FED34A2A80B1, 0x002BB0FFCF14CE62), - new(0x9CCBBE0B53EEB456, 0x013B2AB6FBA4E772), - new(0xCCE9D8AECCAF4903, 0x071AC235C1282FE2), - new(0x6F16B06EC9735FBE, 0x1EBFBDFF82C58EA8), - new(0xE4F1D9CC01F97B59, 0x58B90BFBE8E7BCD5), - new(0x0000000000000000, 0x8000000000000000), - ]; + 0x00002B4C151832AB, 0x0000000000000000, + 0x000561D142DDB787, 0x0000000000000000, + 0x00A2D67FD1C367C8, 0x0000000000000000, + 0x125A7DA057182134, 0x0000000000000000, + 0xF7176BC7BA507C6D, 0x0000000000000001, + 0x088968A28FAC4875, 0x0000000000000033, + 0xA26B9E85115B54C3, 0x00000000000004E3, + 0xA10EC0E8D6AB2988, 0x00000000000070DB, + 0x26AC3C533FCB6035, 0x0000000000098A4B, + 0x8B3687CE8532C06F, 0x0000000000C0B0C9, + 0x7E14C2F18E3A0B6B, 0x000000000E1DEB28, + 0x8DD9260757EE4711, 0x00000000F465639A, + 0xC764FB7ECC717D30, 0x0000000F267A8AC5, + 0x3E1ED2538C4CB47E, 0x000000DA929E9CAF, + 0x11FEC7FF3074CB1A, 0x00000B160111D2E4, + 0x1A1AC54731EE7AD0, 0x00007FF2FF1622C3, + 0xDBD2C2A261AA9A77, 0x00050C244BE1B1E1, + 0x20E2FED34A2A80B1, 0x002BB0FFCF14CE62, + 0x9CCBBE0B53EEB456, 0x013B2AB6FBA4E772, + 0xCCE9D8AECCAF4903, 0x071AC235C1282FE2, + 0x6F16B06EC9735FBE, 0x1EBFBDFF82C58EA8, + 0xE4F1D9CC01F97B59, 0x58B90BFBE8E7BCD5, + 0x0000000000000000, 0x8000000000000000, + ]); /// /// Evaluates the pow log2 polynomial (Intel's EVALUATE_RATIONAL in its POST_MULTIPLY diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs index 1670e2d63a91ac..cb11c1aeeb6254 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs @@ -32,280 +32,526 @@ internal static partial class Number private static DiyFp128 UxThree => new DiyFp128(0, 2, 0xC000_0000_0000_0000, 0); - private readonly struct SqrtCoefficients - { - internal readonly float A; - internal readonly float B; - internal readonly double C; - - internal SqrtCoefficients(float a, float b, double c) - { - A = a; - B = b; - C = c; - } - } - // sqrt_tab_t.c: a*x^2 + b*x + c ~= sqrt(1/x); 256 entries indexed by the low exponent bit and the // high fraction bits. - private static readonly SqrtCoefficients[] s_sqrtTable = + private static ReadOnlySpan SqrtCoefficientsAB => + [ + 2.100767374f, -3.5149509907f, + 2.0604462624f, -3.4743154049f, + 2.0212004185f, -3.4344568253f, + 1.9829931259f, -3.3953547478f, + 1.9457894564f, -3.3569889069f, + 1.9095555544f, -3.319340229f, + 1.8742593527f, -3.2823901176f, + 1.8398698568f, -3.2461204529f, + 1.8063572645f, -3.2105138302f, + 1.7736930847f, -3.1755533218f, + 1.7418498993f, -3.1412229538f, + 1.710801363f, -3.1075065136f, + 1.6805220842f, -3.0743889809f, + 1.6509878635f, -3.0418555737f, + 1.6221753359f, -3.0098922253f, + 1.5940617323f, -2.9784843922f, + 1.5666255951f, -2.9476189613f, + 1.5398460627f, -2.9172832966f, + 1.5137029886f, -2.8874640465f, + 1.4881771803f, -2.8581497669f, + 1.4632499218f, -2.8293278217f, + 1.4389033318f, -2.8009872437f, + 1.4151201248f, -2.7731165886f, + 1.3918836117f, -2.7457051277f, + 1.3691778183f, -2.7187423706f, + 1.3469872475f, -2.6922178268f, + 1.3252968788f, -2.6661219597f, + 1.3040924072f, -2.640444994f, + 1.2833598852f, -2.615177393f, + 1.2630858421f, -2.5903103352f, + 1.2432574034f, -2.5658347607f, + 1.223862052f, -2.5417423248f, + 1.2048876286f, -2.518024683f, + 1.1863225698f, -2.4946734905f, + 1.168155551f, -2.471681118f, + 1.1503756046f, -2.4490396976f, + 1.1329722404f, -2.4267418385f, + 1.1159352064f, -2.4047801495f, + 1.0992547274f, -2.3831479549f, + 1.0829212666f, -2.3618381023f, + 1.0669255257f, -2.3408436775f, + 1.0512586832f, -2.3201589584f, + 1.0359119177f, -2.2997765541f, + 1.0208771229f, -2.2796912193f, + 1.0061459541f, -2.2598962784f, + 9.917107224e-1f, -2.2403864861f, + 9.775637984e-1f, -2.2211556435f, + 9.636977911e-1f, -2.202198267f, + 9.501055479e-1f, -2.1835091114f, + 9.367802143e-1f, -2.1650829315f, + 9.23715055e-1f, -2.1469142437f, + 9.10903573e-1f, -2.1289982796f, + 8.9833951e-1f, -2.1113302708f, + 8.860167265e-1f, -2.0939052105f, + 8.739293218e-1f, -2.0767185688f, + 8.620714545e-1f, -2.0597655773f, + 8.504377007e-1f, -2.0430421829f, + 8.390225172e-1f, -2.0265438557f, + 8.278207183e-1f, -2.010266304f, + 8.16827178e-1f, -1.9942055941f, + 8.060369492e-1f, -1.9783575535f, + 7.954452038e-1f, -1.9627183676f, + 7.850472927e-1f, -1.9472841024f, + 7.748387456e-1f, -1.9320510626f, + 7.648150325e-1f, -1.9170156717f, + 7.549719214e-1f, -1.9021741152f, + 7.453052402e-1f, -1.8875231743f, + 7.358109951e-1f, -1.873059392f, + 7.264851928e-1f, -1.8587793112f, + 7.173240185e-1f, -1.8446798325f, + 7.083238363e-1f, -1.8307577372f, + 6.994808912e-1f, -1.8170098066f, + 6.907917261e-1f, -1.8034330606f, + 6.822529435e-1f, -1.7900246382f, + 6.738612652e-1f, -1.776781559f, + 6.656132936e-1f, -1.7637008429f, + 6.575059891e-1f, -1.7507799864f, + 6.495363116e-1f, -1.7380161285f, + 6.417011619e-1f, -1.7254065275f, + 6.339977384e-1f, -1.7129486799f, + 6.264231205e-1f, -1.7006399632f, + 6.189746261e-1f, -1.6884781122f, + 6.116495132e-1f, -1.6764603853f, + 6.04445219e-1f, -1.6645846367f, + 5.973591805e-1f, -1.6528484821f, + 5.903888941e-1f, -1.6412495375f, + 5.835319161e-1f, -1.6297855377f, + 5.767859221e-1f, -1.6184544563f, + 5.701485872e-1f, -1.6072540283f, + 5.636177063e-1f, -1.5961822271f, + 5.571911335e-1f, -1.5852370262f, + 5.508666039e-1f, -1.5744161606f, + 5.446421504e-1f, -1.5637179613f, + 5.385157466e-1f, -1.5531404018f, + 5.324853659e-1f, -1.5426814556f, + 5.265491009e-1f, -1.5323394537f, + 5.207051039e-1f, -1.5221124887f, + 5.149514675e-1f, -1.5119987726f, + 5.092864633e-1f, -1.5019965172f, + 5.037083626e-1f, -1.4921041727f, + 4.982153773e-1f, -1.4823198318f, + 4.928058982e-1f, -1.4726419449f, + 4.874783158e-1f, -1.4630690813f, + 4.822309911e-1f, -1.4535993338f, + 4.770624042e-1f, -1.4442312717f, + 4.719710648e-1f, -1.4349634647f, + 4.669554532e-1f, -1.425794363f, + 4.620141387e-1f, -1.4167224169f, + 4.571457505e-1f, -1.4077464342f, + 4.523488581e-1f, -1.3988647461f, + 4.476221502e-1f, -1.3900760412f, + 4.429642856e-1f, -1.3813790083f, + 4.383740127e-1f, -1.3727722168f, + 4.3385005e-1f, -1.3642544746f, + 4.293911755e-1f, -1.3558244705f, + 4.249961972e-1f, -1.3474808931f, + 4.206639528e-1f, -1.3392225504f, + 4.1639328e-1f, -1.3310482502f, + 4.121830463e-1f, -1.3229568005f, + 4.080321789e-1f, -1.3149470091f, + 4.039396048e-1f, -1.3070175648f, + 3.999042511e-1f, -1.2991676331f, + 3.959251344e-1f, -1.2913959026f, + 3.920012116e-1f, -1.2837014198f, + 3.881315291e-1f, -1.2760829926f, + 3.843151033e-1f, -1.2685396671f, + 3.805510104e-1f, -1.2610702515f, + 3.768383563e-1f, -1.2536740303f, + 1.4854669571f, -2.4854457378f, + 1.4569555521f, -2.4567120075f, + 1.4292045832f, -2.428527832f, + 1.4021879435f, -2.4008784294f, + 1.3758808374f, -2.3737494946f, + 1.3502596617f, -2.3471279144f, + 1.325301528f, -2.3210003376f, + 1.3009845018f, -2.2953538895f, + 1.2772874832f, -2.2701761723f, + 1.2541904449f, -2.245455265f, + 1.2316738367f, -2.2211799622f, + 1.2097191811f, -2.1973388195f, + 1.1883085966f, -2.1739213467f, + 1.167424798f, -2.1509168148f, + 1.147051096f, -2.1283149719f, + 1.127171874f, -2.1061065197f, + 1.1077716351f, -2.0842814445f, + 1.088835597f, -2.0628306866f, + 1.0703496933f, -2.0417454243f, + 1.0523002148f, -2.0210170746f, + 1.0346739292f, -2.000636816f, + 1.0174583197f, -1.9805971384f, + 1.0006409883f, -1.9608895779f, + 9.84210372e-1f, -1.9415067434f, + 9.681549072e-1f, -1.9224411249f, + 9.524638057e-1f, -1.9036855698f, + 9.371263981e-1f, -1.8852329254f, + 9.221325517e-1f, -1.8670765162f, + 9.074724317e-1f, -1.8492096663f, + 8.931365609e-1f, -1.8316259384f, + 8.791157603e-1f, -1.814319253f, + 8.654011488e-1f, -1.7972832918f, + 8.519842029e-1f, -1.7805122137f, + 8.388567567e-1f, -1.764000535f, + 8.26010704e-1f, -1.7477424145f, + 8.134383559e-1f, -1.7317324877f, + 8.011323214e-1f, -1.7159655094f, + 7.890853286e-1f, -1.7004363537f, + 7.772904634e-1f, -1.6851400137f, + 7.65740931e-1f, -1.6700716019f, + 7.54430294e-1f, -1.6552265882f, + 7.433521152e-1f, -1.640599966f, + 7.325003743e-1f, -1.6261876822f, + 7.218691111e-1f, -1.6119850874f, + 7.114526629e-1f, -1.5979881287f, + 7.012453675e-1f, -1.5841923952f, + 6.912419796e-1f, -1.5705941916f, + 6.81437254e-1f, -1.5571893454f, + 6.718260646e-1f, -1.5439741611f, + 6.624036431e-1f, -1.5309448242f, + 6.531651616e-1f, -1.5180976391f, + 6.441060901e-1f, -1.5054291487f, + 6.352219582e-1f, -1.4929360151f, + 6.265084147e-1f, -1.480614543f, + 6.179613471e-1f, -1.4684617519f, + 6.095765829e-1f, -1.4564743042f, + 6.013502479e-1f, -1.4446489811f, + 5.932785273e-1f, -1.4329829216f, + 5.853576064e-1f, -1.4214729071f, + 5.775840282e-1f, -1.4101163149f, + 5.699541569e-1f, -1.3989100456f, + 5.624647141e-1f, -1.3878514767f, + 5.551123023e-1f, -1.3769378662f, + 5.47893703e-1f, -1.3661663532f, + 5.408058763e-1f, -1.3555346727f, + 5.338457823e-1f, -1.3450403214f, + 5.270103812e-1f, -1.334680438f, + 5.202969313e-1f, -1.3244529963f, + 5.13702631e-1f, -1.3143554926f, + 5.07224679e-1f, -1.3043856621f, + 5.008605719e-1f, -1.2945412397f, + 4.94607687e-1f, -1.2848199606f, + 4.88463521e-1f, -1.2752197981f, + 4.824256897e-1f, -1.2657386065f, + 4.764918387e-1f, -1.2563742399f, + 4.706596732e-1f, -1.2471249104f, + 4.649269581e-1f, -1.2379883528f, + 4.592915177e-1f, -1.2289628983f, + 4.537512362e-1f, -1.2200466394f, + 4.483040869e-1f, -1.2112375498f, + 4.429480433e-1f, -1.2025340796f, + 4.376811683e-1f, -1.1939343214f, + 4.325015247e-1f, -1.1854364872f, + 4.274073243e-1f, -1.1770390272f, + 4.223967195e-1f, -1.1687402725f, + 4.174679816e-1f, -1.1605386734f, + 4.126193523e-1f, -1.1524323225f, + 4.078492224e-1f, -1.1444201469f, + 4.031559229e-1f, -1.1365002394f, + 3.98537904e-1f, -1.1286712885f, + 3.939936161e-1f, -1.1209317446f, + 3.895215094e-1f, -1.1132802963f, + 3.851201832e-1f, -1.1057156324f, + 3.807881474e-1f, -1.098236084f, + 3.765240312e-1f, -1.0908405781f, + 3.723264635e-1f, -1.0835276842f, + 3.681941032e-1f, -1.0762960911f, + 3.641256988e-1f, -1.0691446066f, + 3.601199389e-1f, -1.0620719194f, + 3.561756015e-1f, -1.0550769567f, + 3.522914648e-1f, -1.0481584072f, + 3.484663963e-1f, -1.0413151979f, + 3.44699204e-1f, -1.0345460176f, + 3.409888148e-1f, -1.0278499126f, + 3.373340666e-1f, -1.0212256908f, + 3.337339461e-1f, -1.0146723986f, + 3.301873803e-1f, -1.0081888437f, + 3.266933262e-1f, -1.0017740726f, + 3.2325086e-1f, -9.954270124e-1f, + 3.198589385e-1f, -9.891467094e-1f, + 3.165166676e-1f, -9.8293221e-1f, + 3.132230639e-1f, -9.767824411e-1f, + 3.099772334e-1f, -9.706965685e-1f, + 3.067783117e-1f, -9.646735787e-1f, + 3.036254048e-1f, -9.587126374e-1f, + 3.005177081e-1f, -9.528129101e-1f, + 2.974543273e-1f, -9.469733834e-1f, + 2.944345176e-1f, -9.411932826e-1f, + 2.914574444e-1f, -9.354717731e-1f, + 2.885223329e-1f, -9.29807961e-1f, + 2.85628438e-1f, -9.242010117e-1f, + 2.827750146e-1f, -9.186502695e-1f, + 2.799613476e-1f, -9.131548405e-1f, + 2.771867216e-1f, -9.077140093e-1f, + 2.744504213e-1f, -9.023269415e-1f, + 2.71751821e-1f, -8.969929814e-1f, + 2.690902054e-1f, -8.917113543e-1f, + 2.664649487e-1f, -8.864814043e-1f, + ]; + + private static ReadOnlySpan SqrtCoefficientsC => [ - new(2.100767374f, -3.5149509907f, 2.6464972078561099359), - new(2.0604462624f, -3.4743154049f, 2.6362590670696124814), - new(2.0212004185f, -3.4344568253f, 2.6261388339097704914), - new(1.9829931259f, -3.3953547478f, 2.6161343671734754664), - new(1.9457894564f, -3.3569889069f, 2.6062432760972451132), - new(1.9095555544f, -3.319340229f, 2.596463590697826963), - new(1.8742593527f, -3.2823901176f, 2.5867931995248653203), - new(1.8398698568f, -3.2461204529f, 2.5772300318703730094), - new(1.8063572645f, -3.2105138302f, 2.5677721468918503548), - new(1.7736930847f, -3.1755533218f, 2.5584175687659680947), - new(1.7418498993f, -3.1412229538f, 2.5491646043746129315), - new(1.710801363f, -3.1075065136f, 2.5400111974361759497), - new(1.6805220842f, -3.0743889809f, 2.5309557295054293075), - new(1.6509878635f, -3.0418555737f, 2.5219964300360217983), - new(1.6221753359f, -3.0098922253f, 2.513131738451644744), - new(1.5940617323f, -2.9784843922f, 2.5043597132692148449), - new(1.5666255951f, -2.9476189613f, 2.4956788648540670586), - new(1.5398460627f, -2.9172832966f, 2.4870878496565907177), - new(1.5137029886f, -2.8874640465f, 2.4785847509253505943), - new(1.4881771803f, -2.8581497669f, 2.4701684863694106596), - new(1.4632499218f, -2.8293278217f, 2.4618371919667651739), - new(1.4389033318f, -2.8009872437f, 2.453589741956652739), - new(1.4151201248f, -2.7731165886f, 2.4454245884260308602), - new(1.3918836117f, -2.7457051277f, 2.4373404486694877623), - new(1.3691778183f, -2.7187423706f, 2.4293359837450848466), - new(1.3469872475f, -2.6922178268f, 2.421409733797203716), - new(1.3252968788f, -2.6661219597f, 2.4135606868112681467), - new(1.3040924072f, -2.640444994f, 2.4057874781650356784), - new(1.2833598852f, -2.615177393f, 2.3980887982484154078), - new(1.2630858421f, -2.5903103352f, 2.3904636407379154103), - new(1.2432574034f, -2.5658347607f, 2.3829106727614295971), - new(1.223862052f, -2.5417423248f, 2.3754289062314430029), - new(1.2048876286f, -2.518024683f, 2.368017258199012865), - new(1.1863225698f, -2.4946734905f, 2.3606744506319210228), - new(1.168155551f, -2.471681118f, 2.3533995971537280486), - new(1.1503756046f, -2.4490396976f, 2.3461915565573080325), - new(1.1329722404f, -2.4267418385f, 2.3390493327072075284), - new(1.1159352064f, -2.4047801495f, 2.3319718662505561095), - new(1.0992547274f, -2.3831479549f, 2.3249583958105440118), - new(1.0829212666f, -2.3618381023f, 2.3180077847190338448), - new(1.0669255257f, -2.3408436775f, 2.3111189790671896735), - new(1.0512586832f, -2.3201589584f, 2.3042915357589123534), - new(1.0359119177f, -2.2997765541f, 2.2975239420187385902), - new(1.0208771229f, -2.2796912193f, 2.2908158197682714623), - new(1.0061459541f, -2.2598962784f, 2.2841659744155985018), - new(9.917107224e-1f, -2.2403864861f, 2.2775739037802745675), - new(9.775637984e-1f, -2.2211556435f, 2.2710384627191028825), - new(9.636977911e-1f, -2.202198267f, 2.2645589051141198363), - new(9.501055479e-1f, -2.1835091114f, 2.2581345647863715557), - new(9.367802143e-1f, -2.1650829315f, 2.2517646617865273394), - new(9.23715055e-1f, -2.1469142437f, 2.2454482169670996322), - new(9.10903573e-1f, -2.1289982796f, 2.2391846560382706227), - new(8.9833951e-1f, -2.1113302708f, 2.2329733145353977077), - new(8.860167265e-1f, -2.0939052105f, 2.2268133239115151086), - new(8.739293218e-1f, -2.0767185688f, 2.2207040546088282522), - new(8.620714545e-1f, -2.0597655773f, 2.2146446995886185717), - new(8.504377007e-1f, -2.0430421829f, 2.2086347711853326671), - new(8.390225172e-1f, -2.0265438557f, 2.2026735227736358976), - new(8.278207183e-1f, -2.010266304f, 2.1967602123284747298), - new(8.16827178e-1f, -1.9942055941f, 2.1908943455926404106), - new(8.060369492e-1f, -1.9783575535f, 2.18507517925991311), - new(7.954452038e-1f, -1.9627183676f, 2.179302186449165691), - new(7.850472927e-1f, -1.9472841024f, 2.1735746737563844612), - new(7.748387456e-1f, -1.9320510626f, 2.1678920425681950004), - new(7.648150325e-1f, -1.9170156717f, 2.1622538349306307204), - new(7.549719214e-1f, -1.9021741152f, 2.1566592642242442719), - new(7.453052402e-1f, -1.8875231743f, 2.1511079745610480496), - new(7.358109951e-1f, -1.873059392f, 2.145599345037042738), - new(7.264851928e-1f, -1.8587793112f, 2.140132769235723434), - new(7.173240185e-1f, -1.8446798325f, 2.1347078258028021738), - new(7.083238363e-1f, -1.8307577372f, 2.1293239113956808838), - new(6.994808912e-1f, -1.8170098066f, 2.1239805078667056155), - new(6.907917261e-1f, -1.8034330606f, 2.1186771176963387258), - new(6.822529435e-1f, -1.7900246382f, 2.1134133144277902271), - new(6.738612652e-1f, -1.776781559f, 2.1081885182208226059), - new(6.656132936e-1f, -1.7637008429f, 2.1030022361855264992), - new(6.575059891e-1f, -1.7507799864f, 2.0978541436222885817), - new(6.495363116e-1f, -1.7380161285f, 2.0927436436848862633), - new(6.417011619e-1f, -1.7254065275f, 2.0876702846488341374), - new(6.339977384e-1f, -1.7129486799f, 2.0826336266263057476), - new(6.264231205e-1f, -1.7006399632f, 2.0776332231152411511), - new(6.189746261e-1f, -1.6884781122f, 2.0726687739570012818), - new(6.116495132e-1f, -1.6764603853f, 2.0677396408370174949), - new(6.04445219e-1f, -1.6645846367f, 2.0628455642779957412), - new(5.973591805e-1f, -1.6528484821f, 2.0579861007912311779), - new(5.903888941e-1f, -1.6412495375f, 2.0531607763048084601), - new(5.835319161e-1f, -1.6297855377f, 2.0483691848079983268), - new(5.767859221e-1f, -1.6184544563f, 2.0436110475269988266), - new(5.701485872e-1f, -1.6072540283f, 2.0388858963240143691), - new(5.636177063e-1f, -1.5961822271f, 2.0341933887554151763), - new(5.571911335e-1f, -1.5852370262f, 2.0295331493314230977), - new(5.508666039e-1f, -1.5744161606f, 2.0249046951647516092), - new(5.446421504e-1f, -1.5637179613f, 2.0203078451139786342), - new(5.385157466e-1f, -1.5531404018f, 2.0157421645830040376), - new(5.324853659e-1f, -1.5426814556f, 2.0112072268967735939), - new(5.265491009e-1f, -1.5323394537f, 2.0067028352224858984), - new(5.207051039e-1f, -1.5221124887f, 2.0022285491736880257), - new(5.149514675e-1f, -1.5119987726f, 1.9977840861481438558), - new(5.092864633e-1f, -1.5019965172f, 1.9933690341102592481), - new(5.037083626e-1f, -1.4921041727f, 1.9889831990171957242), - new(4.982153773e-1f, -1.4823198318f, 1.9846261254185282453), - new(4.928058982e-1f, -1.4726419449f, 1.9802975416314198371), - new(4.874783158e-1f, -1.4630690813f, 1.9759972912404571781), - new(4.822309911e-1f, -1.4535993338f, 1.9717248212355455039), - new(4.770624042e-1f, -1.4442312717f, 1.9674799174164367906), - new(4.719710648e-1f, -1.4349634647f, 1.9632623493747335456), - new(4.669554532e-1f, -1.425794363f, 1.9590718106633419305), - new(4.620141387e-1f, -1.4167224169f, 1.9549079267278837445), - new(4.571457505e-1f, -1.4077464342f, 1.9507706079286758533), - new(4.523488581e-1f, -1.3988647461f, 1.9466593832043992863), - new(4.476221502e-1f, -1.3900760412f, 1.9425740155186810364), - new(4.429642856e-1f, -1.3813790083f, 1.9385143007378896051), - new(4.383740127e-1f, -1.3727722168f, 1.9344798518800228645), - new(4.3385005e-1f, -1.3642544746f, 1.9304705373280355767), - new(4.293911755e-1f, -1.3558244705f, 1.9264860679359023007), - new(4.249961972e-1f, -1.3474808931f, 1.9225261331954516221), - new(4.206639528e-1f, -1.3392225504f, 1.9185905143172595161), - new(4.1639328e-1f, -1.3310482502f, 1.9146789988607901377), - new(4.121830463e-1f, -1.3229568005f, 1.910791353422588999), - new(4.080321789e-1f, -1.3149470091f, 1.906927294977383146), - new(4.039396048e-1f, -1.3070175648f, 1.9030864293813255034), - new(3.999042511e-1f, -1.2991676331f, 1.8992688302508556893), - new(3.959251344e-1f, -1.2913959026f, 1.8954740297794357784), - new(3.920012116e-1f, -1.2837014198f, 1.8917019699121535739), - new(3.881315291e-1f, -1.2760829926f, 1.8879522790295079546), - new(3.843151033e-1f, -1.2685396671f, 1.8842248532007704772), - new(3.805510104e-1f, -1.2610702515f, 1.8805192998517419232), - new(3.768383563e-1f, -1.2536740303f, 1.8768356746052303484), - new(1.4854669571f, -2.4854457378f, 1.871356125071838183), - new(1.4569555521f, -2.4567120075f, 1.8641166687132670675), - new(1.4292045832f, -2.428527832f, 1.8569606236933505757), - new(1.4021879435f, -2.4008784294f, 1.8498863686852736748), - new(1.3758808374f, -2.3737494946f, 1.8428922507547075664), - new(1.3502596617f, -2.3471279144f, 1.8359769806847199525), - new(1.325301528f, -2.3210003376f, 1.8291390187728028981), - new(1.3009845018f, -2.2953538895f, 1.8223768737350841104), - new(1.2772874832f, -2.2701761723f, 1.815689132437547343), - new(1.2541904449f, -2.245455265f, 1.809074389036413347), - new(1.2316738367f, -2.2211799622f, 1.8025315409735020248), - new(1.2097191811f, -2.1973388195f, 1.7960591016834552054), - new(1.1883085966f, -2.1739213467f, 1.7896559762998277295), - new(1.167424798f, -2.1509168148f, 1.7833208136393936618), - new(1.147051096f, -2.1283149719f, 1.7770523917027898587), - new(1.127171874f, -2.1061065197f, 1.7708497362122495347), - new(1.1077716351f, -2.0842814445f, 1.7647114820879259773), - new(1.088835597f, -2.0628306866f, 1.7586366171474150025), - new(1.0703496933f, -2.0417454243f, 1.7526240797610809654), - new(1.0523002148f, -2.0210170746f, 1.7466728702670488513), - new(1.0346739292f, -2.000636816f, 1.7407817347114710224), - new(1.0174583197f, -1.9805971384f, 1.7349499768352952281), - new(1.0006409883f, -1.9608895779f, 1.7291763454114605346), - new(9.84210372e-1f, -1.9415067434f, 1.7234599651286684451), - new(9.681549072e-1f, -1.9224411249f, 1.7177999276044314068), - new(9.524638057e-1f, -1.9036855698f, 1.7121952995670224557), - new(9.371263981e-1f, -1.8852329254f, 1.7066451378027783911), - new(9.221325517e-1f, -1.8670765162f, 1.7011486250045946347), - new(9.074724317e-1f, -1.8492096663f, 1.6957048668596548409), - new(8.931365609e-1f, -1.8316259384f, 1.6903130118241380172), - new(8.791157603e-1f, -1.814319253f, 1.6849723465254846025), - new(8.654011488e-1f, -1.7972832918f, 1.6796819267645029511), - new(8.519842029e-1f, -1.7805122137f, 1.6744409931168894178), - new(8.388567567e-1f, -1.764000535f, 1.6692488987058947262), - new(8.26010704e-1f, -1.7477424145f, 1.6641047757586507034), - new(8.134383559e-1f, -1.7317324877f, 1.6590079164589084853), - new(8.011323214e-1f, -1.7159655094f, 1.6539575934764306191), - new(7.890853286e-1f, -1.7004363537f, 1.6489531316451486699), - new(7.772904634e-1f, -1.6851400137f, 1.6439938084540918454), - new(7.65740931e-1f, -1.6700716019f, 1.6390789513374663373), - new(7.54430294e-1f, -1.6552265882f, 1.6342079924882827583), - new(7.433521152e-1f, -1.640599966f, 1.6293800727691609523), - new(7.325003743e-1f, -1.6261876822f, 1.6245948018384631785), - new(7.218691111e-1f, -1.6119850874f, 1.6198513899786671981), - new(7.114526629e-1f, -1.5979881287f, 1.6151493315598057127), - new(7.012453675e-1f, -1.5841923952f, 1.6104879010099405966), - new(6.912419796e-1f, -1.5705941916f, 1.6058666848488655604), - new(6.81437254e-1f, -1.5571893454f, 1.6012849649345869714), - new(6.718260646e-1f, -1.5439741611f, 1.5967423114398499921), - new(6.624036431e-1f, -1.5309448242f, 1.5922380624986197111), - new(6.531651616e-1f, -1.5180976391f, 1.5877716826712331308), - new(6.441060901e-1f, -1.5054291487f, 1.5833426759719316743), - new(6.352219582e-1f, -1.4929360151f, 1.5789506181480670004), - new(6.265084147e-1f, -1.480614543f, 1.5745947905777103973), - new(6.179613471e-1f, -1.4684617519f, 1.570274875471304932), - new(6.095765829e-1f, -1.4564743042f, 1.5659903484686081951), - new(6.013502479e-1f, -1.4446489811f, 1.5617406323590747495), - new(5.932785273e-1f, -1.4329829216f, 1.5575253900948081031), - new(5.853576064e-1f, -1.4214729071f, 1.5533440417087493947), - new(5.775840282e-1f, -1.4101163149f, 1.5491962650252339879), - new(5.699541569e-1f, -1.3989100456f, 1.5450814989506893378), - new(5.624647141e-1f, -1.3878514767f, 1.5409993522652318865), - new(5.551123023e-1f, -1.3769378662f, 1.5369494240783051614), - new(5.47893703e-1f, -1.3661663532f, 1.5329311391076325034), - new(5.408058763e-1f, -1.3555346727f, 1.5289442788899148577), - new(5.338457823e-1f, -1.3450403214f, 1.5249884604662240707), - new(5.270103812e-1f, -1.334680438f, 1.521063041989517595), - new(5.202969313e-1f, -1.3244529963f, 1.5171678531392449385), - new(5.13702631e-1f, -1.3143554926f, 1.5133024075264445992), - new(5.07224679e-1f, -1.3043856621f, 1.5094664122566117415), - new(5.008605719e-1f, -1.2945412397f, 1.5056594093099230809), - new(4.94607687e-1f, -1.2848199606f, 1.5018810206540535668), - new(4.88463521e-1f, -1.2752197981f, 1.4981309930501513768), - new(4.824256897e-1f, -1.2657386065f, 1.4944089182854788839), - new(4.764918387e-1f, -1.2563742399f, 1.4907143780999090563), - new(4.706596732e-1f, -1.2471249104f, 1.4870472093725845196), - new(4.649269581e-1f, -1.2379883528f, 1.4834068433059228038), - new(4.592915177e-1f, -1.2289628983f, 1.4797931561207488266), - new(4.537512362e-1f, -1.2200466394f, 1.4762058063267732164), - new(4.483040869e-1f, -1.2112375498f, 1.4726443058277337136), - new(4.429480433e-1f, -1.2025340796f, 1.4691085600971758164), - new(4.376811683e-1f, -1.1939343214f, 1.4655981352796467727), - new(4.325015247e-1f, -1.1854364872f, 1.4621127014366889476), - new(4.274073243e-1f, -1.1770390272f, 1.4586520321860682406), - new(4.223967195e-1f, -1.1687402725f, 1.4552158519568947109), - new(4.174679816e-1f, -1.1605386734f, 1.4518039105558124454), - new(4.126193523e-1f, -1.1524323225f, 1.4484156871910555038), - new(4.078492224e-1f, -1.1444201469f, 1.4450512617287648647), - new(4.031559229e-1f, -1.1365002394f, 1.4417100643518224091), - new(3.98537904e-1f, -1.1286712885f, 1.43839194797809445), - new(3.939936161e-1f, -1.1209317446f, 1.4350965710114598912), - new(3.895215094e-1f, -1.1132802963f, 1.4318238019615985585), - new(3.851201832e-1f, -1.1057156324f, 1.4285734086210110129), - new(3.807881474e-1f, -1.098236084f, 1.4253449225241264339), - new(3.765240312e-1f, -1.0908405781f, 1.4221383066615875423), - new(3.723264635e-1f, -1.0835276842f, 1.4189532217380030405), - new(3.681941032e-1f, -1.0762960911f, 1.4157894148082008431), - new(3.641256988e-1f, -1.0691446066f, 1.4126466747119955184), - new(3.601199389e-1f, -1.0620719194f, 1.4095247373925208624), - new(3.561756015e-1f, -1.0550769567f, 1.4064234861092870078), - new(3.522914648e-1f, -1.0481584072f, 1.4033425989626974058), - new(3.484663963e-1f, -1.0413151979f, 1.4002819001954518572), - new(3.44699204e-1f, -1.0345460176f, 1.3972410535131558575), - new(3.409888148e-1f, -1.0278499126f, 1.394219952616180338), - new(3.373340666e-1f, -1.0212256908f, 1.391218355036795814), - new(3.337339461e-1f, -1.0146723986f, 1.3882361175316319908), - new(3.301873803e-1f, -1.0081888437f, 1.3852729339966112391), - new(3.266933262e-1f, -1.0017740726f, 1.3823286962165541327), - new(3.2325086e-1f, -9.954270124e-1f, 1.3794030910528882689), - new(3.198589385e-1f, -9.891467094e-1f, 1.376496020486553263), - new(3.165166676e-1f, -9.8293221e-1f, 1.3736072646635312246), - new(3.132230639e-1f, -9.767824411e-1f, 1.3707365738998594498), - new(3.099772334e-1f, -9.706965685e-1f, 1.3678838480300629548), - new(3.067783117e-1f, -9.646735787e-1f, 1.3650487974920465694), - new(3.036254048e-1f, -9.587126374e-1f, 1.3622313312325788012), - new(3.005177081e-1f, -9.528129101e-1f, 1.3594312836070771906), - new(2.974543273e-1f, -9.469733834e-1f, 1.3566484036263514053), - new(2.944345176e-1f, -9.411932826e-1f, 1.3538825358839141819), - new(2.914574444e-1f, -9.354717731e-1f, 1.3511335539557793246), - new(2.885223329e-1f, -9.29807961e-1f, 1.3484012235283039004), - new(2.85628438e-1f, -9.242010117e-1f, 1.3456853430080564922), - new(2.827750146e-1f, -9.186502695e-1f, 1.3429858882576752713), - new(2.799613476e-1f, -9.131548405e-1f, 1.3403025794889820102), - new(2.771867216e-1f, -9.077140093e-1f, 1.3376353143324014318), - new(2.744504213e-1f, -9.023269415e-1f, 1.334983877577370644), - new(2.71751821e-1f, -8.969929814e-1f, 1.3323481464845465569), - new(2.690902054e-1f, -8.917113543e-1f, 1.3297279714586007491), - new(2.664649487e-1f, -8.864814043e-1f, 1.3271232372059093815), + 2.6464972078561099359, + 2.6362590670696124814, + 2.6261388339097704914, + 2.6161343671734754664, + 2.6062432760972451132, + 2.596463590697826963, + 2.5867931995248653203, + 2.5772300318703730094, + 2.5677721468918503548, + 2.5584175687659680947, + 2.5491646043746129315, + 2.5400111974361759497, + 2.5309557295054293075, + 2.5219964300360217983, + 2.513131738451644744, + 2.5043597132692148449, + 2.4956788648540670586, + 2.4870878496565907177, + 2.4785847509253505943, + 2.4701684863694106596, + 2.4618371919667651739, + 2.453589741956652739, + 2.4454245884260308602, + 2.4373404486694877623, + 2.4293359837450848466, + 2.421409733797203716, + 2.4135606868112681467, + 2.4057874781650356784, + 2.3980887982484154078, + 2.3904636407379154103, + 2.3829106727614295971, + 2.3754289062314430029, + 2.368017258199012865, + 2.3606744506319210228, + 2.3533995971537280486, + 2.3461915565573080325, + 2.3390493327072075284, + 2.3319718662505561095, + 2.3249583958105440118, + 2.3180077847190338448, + 2.3111189790671896735, + 2.3042915357589123534, + 2.2975239420187385902, + 2.2908158197682714623, + 2.2841659744155985018, + 2.2775739037802745675, + 2.2710384627191028825, + 2.2645589051141198363, + 2.2581345647863715557, + 2.2517646617865273394, + 2.2454482169670996322, + 2.2391846560382706227, + 2.2329733145353977077, + 2.2268133239115151086, + 2.2207040546088282522, + 2.2146446995886185717, + 2.2086347711853326671, + 2.2026735227736358976, + 2.1967602123284747298, + 2.1908943455926404106, + 2.18507517925991311, + 2.179302186449165691, + 2.1735746737563844612, + 2.1678920425681950004, + 2.1622538349306307204, + 2.1566592642242442719, + 2.1511079745610480496, + 2.145599345037042738, + 2.140132769235723434, + 2.1347078258028021738, + 2.1293239113956808838, + 2.1239805078667056155, + 2.1186771176963387258, + 2.1134133144277902271, + 2.1081885182208226059, + 2.1030022361855264992, + 2.0978541436222885817, + 2.0927436436848862633, + 2.0876702846488341374, + 2.0826336266263057476, + 2.0776332231152411511, + 2.0726687739570012818, + 2.0677396408370174949, + 2.0628455642779957412, + 2.0579861007912311779, + 2.0531607763048084601, + 2.0483691848079983268, + 2.0436110475269988266, + 2.0388858963240143691, + 2.0341933887554151763, + 2.0295331493314230977, + 2.0249046951647516092, + 2.0203078451139786342, + 2.0157421645830040376, + 2.0112072268967735939, + 2.0067028352224858984, + 2.0022285491736880257, + 1.9977840861481438558, + 1.9933690341102592481, + 1.9889831990171957242, + 1.9846261254185282453, + 1.9802975416314198371, + 1.9759972912404571781, + 1.9717248212355455039, + 1.9674799174164367906, + 1.9632623493747335456, + 1.9590718106633419305, + 1.9549079267278837445, + 1.9507706079286758533, + 1.9466593832043992863, + 1.9425740155186810364, + 1.9385143007378896051, + 1.9344798518800228645, + 1.9304705373280355767, + 1.9264860679359023007, + 1.9225261331954516221, + 1.9185905143172595161, + 1.9146789988607901377, + 1.910791353422588999, + 1.906927294977383146, + 1.9030864293813255034, + 1.8992688302508556893, + 1.8954740297794357784, + 1.8917019699121535739, + 1.8879522790295079546, + 1.8842248532007704772, + 1.8805192998517419232, + 1.8768356746052303484, + 1.871356125071838183, + 1.8641166687132670675, + 1.8569606236933505757, + 1.8498863686852736748, + 1.8428922507547075664, + 1.8359769806847199525, + 1.8291390187728028981, + 1.8223768737350841104, + 1.815689132437547343, + 1.809074389036413347, + 1.8025315409735020248, + 1.7960591016834552054, + 1.7896559762998277295, + 1.7833208136393936618, + 1.7770523917027898587, + 1.7708497362122495347, + 1.7647114820879259773, + 1.7586366171474150025, + 1.7526240797610809654, + 1.7466728702670488513, + 1.7407817347114710224, + 1.7349499768352952281, + 1.7291763454114605346, + 1.7234599651286684451, + 1.7177999276044314068, + 1.7121952995670224557, + 1.7066451378027783911, + 1.7011486250045946347, + 1.6957048668596548409, + 1.6903130118241380172, + 1.6849723465254846025, + 1.6796819267645029511, + 1.6744409931168894178, + 1.6692488987058947262, + 1.6641047757586507034, + 1.6590079164589084853, + 1.6539575934764306191, + 1.6489531316451486699, + 1.6439938084540918454, + 1.6390789513374663373, + 1.6342079924882827583, + 1.6293800727691609523, + 1.6245948018384631785, + 1.6198513899786671981, + 1.6151493315598057127, + 1.6104879010099405966, + 1.6058666848488655604, + 1.6012849649345869714, + 1.5967423114398499921, + 1.5922380624986197111, + 1.5877716826712331308, + 1.5833426759719316743, + 1.5789506181480670004, + 1.5745947905777103973, + 1.570274875471304932, + 1.5659903484686081951, + 1.5617406323590747495, + 1.5575253900948081031, + 1.5533440417087493947, + 1.5491962650252339879, + 1.5450814989506893378, + 1.5409993522652318865, + 1.5369494240783051614, + 1.5329311391076325034, + 1.5289442788899148577, + 1.5249884604662240707, + 1.521063041989517595, + 1.5171678531392449385, + 1.5133024075264445992, + 1.5094664122566117415, + 1.5056594093099230809, + 1.5018810206540535668, + 1.4981309930501513768, + 1.4944089182854788839, + 1.4907143780999090563, + 1.4870472093725845196, + 1.4834068433059228038, + 1.4797931561207488266, + 1.4762058063267732164, + 1.4726443058277337136, + 1.4691085600971758164, + 1.4655981352796467727, + 1.4621127014366889476, + 1.4586520321860682406, + 1.4552158519568947109, + 1.4518039105558124454, + 1.4484156871910555038, + 1.4450512617287648647, + 1.4417100643518224091, + 1.43839194797809445, + 1.4350965710114598912, + 1.4318238019615985585, + 1.4285734086210110129, + 1.4253449225241264339, + 1.4221383066615875423, + 1.4189532217380030405, + 1.4157894148082008431, + 1.4126466747119955184, + 1.4095247373925208624, + 1.4064234861092870078, + 1.4033425989626974058, + 1.4002819001954518572, + 1.3972410535131558575, + 1.394219952616180338, + 1.391218355036795814, + 1.3882361175316319908, + 1.3852729339966112391, + 1.3823286962165541327, + 1.3794030910528882689, + 1.376496020486553263, + 1.3736072646635312246, + 1.3707365738998594498, + 1.3678838480300629548, + 1.3650487974920465694, + 1.3622313312325788012, + 1.3594312836070771906, + 1.3566484036263514053, + 1.3538825358839141819, + 1.3511335539557793246, + 1.3484012235283039004, + 1.3456853430080564922, + 1.3429858882576752713, + 1.3403025794889820102, + 1.3376353143324014318, + 1.334983877577370644, + 1.3323481464845465569, + 1.3297279714586007491, + 1.3271232372059093815, ]; private static DiyFp128 DiyFp128Sqrt(DiyFp128 x) @@ -329,8 +575,10 @@ private static DiyFp128 DiyFp128Sqrt(DiyFp128 x) // The exponent parity is swapped into the table index so the reduced result lands in [1, 2). int index = ((int)(msd >> (64 - SqrtNumFractionBits - 1)) & 0xFF) ^ (parity << SqrtNumFractionBits); - SqrtCoefficients p = s_sqrtTable[index]; - double g = (((double)p.A) * (f * f)) + ((((double)p.B) * f) + p.C); + ReadOnlySpan coefficientsAB = SqrtCoefficientsAB; + ReadOnlySpan coefficientsC = SqrtCoefficientsC; + int coefficientsABIndex = index * 2; + double g = (((double)coefficientsAB[coefficientsABIndex]) * (f * f)) + ((((double)coefficientsAB[coefficientsABIndex + 1]) * f) + coefficientsC[index]); g *= SqrtRootTwo; f = fHi + fLo; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Trig.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Trig.cs index 4a9dc38d834f74..de4666e7afbd92 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Trig.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Trig.cs @@ -48,65 +48,65 @@ internal static partial class Number // Unpacked pi/4 (dpml_trig_x.h) and pi (pi/4 with binary exponent + 2). private static DiyFp128 TrigPiOverFour => new DiyFp128(0, 0, 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1); - private static readonly DiyFp128FixedCoefficient[] TrigSinCoefficients = + private static ReadOnlySpan TrigSinCoefficients => DiyFp128FixedCoefficients( [ - new(0x000000039E634562, 0x0000000000000000), - new(0x000009F9DCE17A1D, 0x0000000000000000), - new(0x001761B4083A3075, 0x0000000000000000), - new(0x2E371DEDB1D75408, 0x0000000000000000), - new(0xD26D1A05013C755B, 0x000000000000004B), - new(0x1DC0C2B528320429, 0x000000000000654B), - new(0x9CCEE07C4701FACD, 0x00000000006B9FCF), - new(0xA1B425F28DFBF381, 0x000000005849184E), - new(0x89C71FCE8FC76DB3, 0x00000035CC8ACFEA), - new(0x338FAAC1C88E2826, 0x0000171DE3A556C7), - new(0x8068068068067E8F, 0x0006806806806806), - new(0x1111111111111106, 0x0111111111111111), - new(0x5555555555555555, 0x1555555555555555), - new(0x0000000000000000, 0x8000000000000000), - ]; - - private static readonly DiyFp128FixedCoefficient[] TrigCosCoefficients = + 0x000000039E634562, 0x0000000000000000, + 0x000009F9DCE17A1D, 0x0000000000000000, + 0x001761B4083A3075, 0x0000000000000000, + 0x2E371DEDB1D75408, 0x0000000000000000, + 0xD26D1A05013C755B, 0x000000000000004B, + 0x1DC0C2B528320429, 0x000000000000654B, + 0x9CCEE07C4701FACD, 0x00000000006B9FCF, + 0xA1B425F28DFBF381, 0x000000005849184E, + 0x89C71FCE8FC76DB3, 0x00000035CC8ACFEA, + 0x338FAAC1C88E2826, 0x0000171DE3A556C7, + 0x8068068068067E8F, 0x0006806806806806, + 0x1111111111111106, 0x0111111111111111, + 0x5555555555555555, 0x1555555555555555, + 0x0000000000000000, 0x8000000000000000, + ]); + + private static ReadOnlySpan TrigCosCoefficients => DiyFp128FixedCoefficients( [ - new(0x00000061A9FB87E2, 0x0000000000000000), - new(0x0000F96669688C7C, 0x0000000000000000), - new(0x0219C72C77C1DE0C, 0x0000000000000000), - new(0xCA85747F51903A09, 0x0000000000000003), - new(0x9E18EE5EEB393833, 0x00000000000005A0), - new(0xF9CCEE079837094C, 0x000000000006B9FC), - new(0x301F274823772903, 0x00000000064E5D2A), - new(0x3625ED5134A72FA4, 0x000000047BB63BFE), - new(0xEB8E5DE02D6A41E7, 0x0000024FC9F6EF13), - new(0xD00D00D00CFBFFE1, 0x0000D00D00D00D00), - new(0x82D82D82D82D4910, 0x002D82D82D82D82D), - new(0x55555555555553EB, 0x0555555555555555), - new(0xFFFFFFFFFFFFFFFC, 0x3FFFFFFFFFFFFFFF), - new(0x0000000000000000, 0x8000000000000000), - ]; - - private static readonly DiyFp128FixedCoefficient[] TrigTanNumeratorCoefficients = + 0x00000061A9FB87E2, 0x0000000000000000, + 0x0000F96669688C7C, 0x0000000000000000, + 0x0219C72C77C1DE0C, 0x0000000000000000, + 0xCA85747F51903A09, 0x0000000000000003, + 0x9E18EE5EEB393833, 0x00000000000005A0, + 0xF9CCEE079837094C, 0x000000000006B9FC, + 0x301F274823772903, 0x00000000064E5D2A, + 0x3625ED5134A72FA4, 0x000000047BB63BFE, + 0xEB8E5DE02D6A41E7, 0x0000024FC9F6EF13, + 0xD00D00D00CFBFFE1, 0x0000D00D00D00D00, + 0x82D82D82D82D4910, 0x002D82D82D82D82D, + 0x55555555555553EB, 0x0555555555555555, + 0xFFFFFFFFFFFFFFFC, 0x3FFFFFFFFFFFFFFF, + 0x0000000000000000, 0x8000000000000000, + ]); + + private static ReadOnlySpan TrigTanNumeratorCoefficients => DiyFp128FixedCoefficients( [ - new(0x0000000000000000, 0x0000000000000000), - new(0x02E36384AB86D966, 0x00000000004583DC), - new(0xFE661C77C57437CF, 0x00000001DF2FB0D7), - new(0xE5F9C2190062EE42, 0x0000036F46CAE26E), - new(0x9C878717E15A162F, 0x000269DCA6FA2240), - new(0xC5B462FFE65127B0, 0x00B209C04C0B8A2C), - new(0xA273C25867F59A68, 0x12F6C9C3D7A587C9), - new(0x0000000000000000, 0x8000000000000000), - ]; - - private static readonly DiyFp128FixedCoefficient[] TrigTanDenominatorCoefficients = + 0x0000000000000000, 0x0000000000000000, + 0x02E36384AB86D966, 0x00000000004583DC, + 0xFE661C77C57437CF, 0x00000001DF2FB0D7, + 0xE5F9C2190062EE42, 0x0000036F46CAE26E, + 0x9C878717E15A162F, 0x000269DCA6FA2240, + 0xC5B462FFE65127B0, 0x00B209C04C0B8A2C, + 0xA273C25867F59A68, 0x12F6C9C3D7A587C9, + 0x0000000000000000, 0x8000000000000000, + ]); + + private static ReadOnlySpan TrigTanDenominatorCoefficients => DiyFp128FixedCoefficients( [ - new(0x196C967ACBFC02D6, 0x000000000000A9BA), - new(0xD03D3831CF5F2FE6, 0x000000000E1AE92D), - new(0x40A36A10FD241F97, 0x0000002E4C98A51D), - new(0xB12A527E72E00402, 0x0000338085B96B4F), - new(0xF5E92D642C15CBC5, 0x001739C356378673), - new(0x7902CB9A86202DFC, 0x042C1F7EBBBFDF42), - new(0x4D1E6D0312A04513, 0x3DA1746E82503274), - new(0x0000000000000000, 0x8000000000000000), - ]; + 0x196C967ACBFC02D6, 0x000000000000A9BA, + 0xD03D3831CF5F2FE6, 0x000000000E1AE92D, + 0x40A36A10FD241F97, 0x0000002E4C98A51D, + 0xB12A527E72E00402, 0x0000338085B96B4F, + 0xF5E92D642C15CBC5, 0x001739C356378673, + 0x7902CB9A86202DFC, 0x042C1F7EBBBFDF42, + 0x4D1E6D0312A04513, 0x3DA1746E82503274, + 0x0000000000000000, 0x8000000000000000, + ]); // dpml_four_over_pi.c: the leading 263 x 64-bit digits of 4/pi (with two words of zero padding). private static ReadOnlySpan TrigFourOverPi => diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.Transcendental.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.Transcendental.cs index 69d4fcc2367106..f1a98c135e94c8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.Transcendental.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.Transcendental.cs @@ -1133,7 +1133,7 @@ internal static TValue AtanDecimalIeee754(TValue x) return ConvertFloatToDecimalIeee754(double.CopySign(double.Pi / 2.0, signed ? -1.0 : 1.0)); } - DiyFp128 halfPi = InvTrigConstants[2]; + DiyFp128 halfPi = GetInvTrigConstant(2); halfPi._sign = signed ? UxSignBit : 0; return DiyFp128ToDecimal(halfPi); } @@ -1222,7 +1222,7 @@ internal static TValue AcosDecimalIeee754(TValue x) { return ConvertFloatToDecimalIeee754(double.Pi / 2.0); } - return DiyFp128ToDecimal(InvTrigConstants[2]); + return DiyFp128ToDecimal(GetInvTrigConstant(2)); } if (DecimalIeee754UsesDouble()) @@ -1280,22 +1280,22 @@ internal static TValue Atan2DecimalIeee754(TValue y, TValue x) if (yInfinity) { // atan2(+/-inf, +/-inf) = +/-3pi/4 or +/-pi/4; atan2(+/-inf, finite) = +/-pi/2. - magnitude = xInfinity ? (decodedX.Signed ? InvTrigConstants[3] : InvTrigConstants[1]) : InvTrigConstants[2]; + magnitude = xInfinity ? (decodedX.Signed ? GetInvTrigConstant(3) : GetInvTrigConstant(1)) : GetInvTrigConstant(2); } else if (xInfinity) { // atan2(+/-finite, -inf) = +/-pi; atan2(+/-finite, +inf) = +/-0. - magnitude = decodedX.Signed ? InvTrigConstants[4] : InvTrigConstants[0]; + magnitude = decodedX.Signed ? GetInvTrigConstant(4) : GetInvTrigConstant(0); } else if (yZero) { // atan2(+/-0, x<0 or -0) = +/-pi; atan2(+/-0, x>=0) = +/-0. - magnitude = decodedX.Signed ? InvTrigConstants[4] : InvTrigConstants[0]; + magnitude = decodedX.Signed ? GetInvTrigConstant(4) : GetInvTrigConstant(0); } else { // xZero, finite non-zero y: atan2(+/-y, +/-0) = +/-pi/2. - magnitude = InvTrigConstants[2]; + magnitude = GetInvTrigConstant(2); } magnitude._sign = decodedY.Signed ? UxSignBit : 0; @@ -1478,7 +1478,7 @@ internal static TValue AtanPiDecimalIeee754(TValue x) return ConvertFloatToDecimalIeee754(double.CopySign(0.5, signed ? -1.0 : 1.0)); } - DiyFp128 half = PiFractionConstants[2]; + DiyFp128 half = GetPiFractionConstant(2); half._sign = signed ? UxSignBit : 0; return DiyFp128ToDecimal(half); } @@ -1498,7 +1498,7 @@ internal static TValue AtanPiDecimalIeee754(TValue x) } DiyFp128 argument = DecimalToDiyFp128(decoded.Signed, decoded.UnbiasedExponent, decoded.Significand); - DiyFp128Divide(DiyFp128Atan(argument), InvTrigConstants[4], DiyFp128FullPrecision, out DiyFp128 result); + DiyFp128Divide(DiyFp128Atan(argument), GetInvTrigConstant(4), DiyFp128FullPrecision, out DiyFp128 result); return DiyFp128ToDecimal(result); } @@ -1541,7 +1541,7 @@ internal static TValue AsinPiDecimalIeee754(TValue x) return TDecimal.NaNMask; } - DiyFp128Divide(DiyFp128Asin(argument), InvTrigConstants[4], DiyFp128FullPrecision, out DiyFp128 quotient); + DiyFp128Divide(DiyFp128Asin(argument), GetInvTrigConstant(4), DiyFp128FullPrecision, out DiyFp128 quotient); return DiyFp128ToDecimal(quotient); } @@ -1570,7 +1570,7 @@ internal static TValue AcosPiDecimalIeee754(TValue x) { return ConvertFloatToDecimalIeee754(0.5); } - return DiyFp128ToDecimal(PiFractionConstants[2]); + return DiyFp128ToDecimal(GetPiFractionConstant(2)); } if (DecimalIeee754UsesDouble()) @@ -1588,7 +1588,7 @@ internal static TValue AcosPiDecimalIeee754(TValue x) return TDecimal.NaNMask; } - DiyFp128Divide(DiyFp128Acos(argument), InvTrigConstants[4], DiyFp128FullPrecision, out DiyFp128 quotient); + DiyFp128Divide(DiyFp128Acos(argument), GetInvTrigConstant(4), DiyFp128FullPrecision, out DiyFp128 quotient); return DiyFp128ToDecimal(quotient); } @@ -1631,22 +1631,22 @@ internal static TValue Atan2PiDecimalIeee754(TValue y, TValue if (yInfinity) { // atan2Pi(+/-inf, +/-inf) = +/-3/4 or +/-1/4; atan2Pi(+/-inf, finite) = +/-1/2. - magnitude = xInfinity ? (decodedX.Signed ? PiFractionConstants[3] : PiFractionConstants[1]) : PiFractionConstants[2]; + magnitude = xInfinity ? (decodedX.Signed ? GetPiFractionConstant(3) : GetPiFractionConstant(1)) : GetPiFractionConstant(2); } else if (xInfinity) { // atan2Pi(+/-finite, -inf) = +/-1; atan2Pi(+/-finite, +inf) = +/-0. - magnitude = decodedX.Signed ? PiFractionConstants[4] : PiFractionConstants[0]; + magnitude = decodedX.Signed ? GetPiFractionConstant(4) : GetPiFractionConstant(0); } else if (yZero) { // atan2Pi(+/-0, x<0 or -0) = +/-1; atan2Pi(+/-0, x>=0) = +/-0. - magnitude = decodedX.Signed ? PiFractionConstants[4] : PiFractionConstants[0]; + magnitude = decodedX.Signed ? GetPiFractionConstant(4) : GetPiFractionConstant(0); } else { // xZero, finite non-zero y: atan2Pi(+/-y, +/-0) = +/-1/2. - magnitude = PiFractionConstants[2]; + magnitude = GetPiFractionConstant(2); } magnitude._sign = decodedY.Signed ? UxSignBit : 0; @@ -1655,7 +1655,7 @@ internal static TValue Atan2PiDecimalIeee754(TValue y, TValue DiyFp128 argumentY = DecimalToDiyFp128(decodedY.Signed, decodedY.UnbiasedExponent, decodedY.Significand); DiyFp128 argumentX = DecimalToDiyFp128(decodedX.Signed, decodedX.UnbiasedExponent, decodedX.Significand); - DiyFp128Divide(DiyFp128Atan2(argumentY, argumentX, haveX: true), InvTrigConstants[4], DiyFp128FullPrecision, out DiyFp128 result); + DiyFp128Divide(DiyFp128Atan2(argumentY, argumentX, haveX: true), GetInvTrigConstant(4), DiyFp128FullPrecision, out DiyFp128 result); return DiyFp128ToDecimal(result); } 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 2541286461ee5c..687ae6df61d663 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -254,7 +254,7 @@ internal static partial class Number { internal const int DecimalPrecision = 29; // Decimal.DecCalc also uses this value - /// The non-inclusive upper bound of . + /// The non-inclusive upper bound of . /// /// This is a semi-arbitrary bound. For mono, which is often used for more size-constrained workloads, /// we keep the size really small, supporting only single digit values. For coreclr, we use a larger @@ -269,39 +269,46 @@ internal static partial class Number #else 300; #endif - /// Lazily-populated cache of strings for uint values in the range [0, ). - private static readonly string?[] s_smallNumberCache = new string[SmallNumberCacheLength]; + private static class SmallNumberCache + { + /// Lazily-populated cache of strings for uint values in the range [0, ). + internal static readonly string?[] Value = new string[SmallNumberCacheLength]; + } // Optimizations using "TwoDigits" inspired by: // https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c/ #if MONO // Workaround for a performance regression on Mono: https://github.com/dotnet/runtime/issues/111932 - private static readonly byte[] TwoDigitsCharsAsBytes = - MemoryMarshal.AsBytes("00010203040506070809" + - "10111213141516171819" + - "20212223242526272829" + - "30313233343536373839" + - "40414243444546474849" + - "50515253545556575859" + - "60616263646566676869" + - "70717273747576777879" + - "80818283848586878889" + - "90919293949596979899").ToArray(); - private static readonly byte[] TwoDigitsBytes = - ("00010203040506070809"u8 + - "10111213141516171819"u8 + - "20212223242526272829"u8 + - "30313233343536373839"u8 + - "40414243444546474849"u8 + - "50515253545556575859"u8 + - "60616263646566676869"u8 + - "70717273747576777879"u8 + - "80818283848586878889"u8 + - "90919293949596979899"u8).ToArray(); + private static class TwoDigitsCache + { + internal static readonly byte[] CharsAsBytes = + MemoryMarshal.AsBytes("00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899").ToArray(); + + internal static readonly byte[] Bytes = + ("00010203040506070809"u8 + + "10111213141516171819"u8 + + "20212223242526272829"u8 + + "30313233343536373839"u8 + + "40414243444546474849"u8 + + "50515253545556575859"u8 + + "60616263646566676869"u8 + + "70717273747576777879"u8 + + "80818283848586878889"u8 + + "90919293949596979899"u8).ToArray(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ref byte GetTwoDigitsBytesRef(bool useChars) => - ref MemoryMarshal.GetArrayDataReference(useChars ? TwoDigitsCharsAsBytes : TwoDigitsBytes); + ref MemoryMarshal.GetArrayDataReference(useChars ? TwoDigitsCache.CharsAsBytes : TwoDigitsCache.Bytes); #else private static ReadOnlySpan TwoDigitsCharsAsBytes => MemoryMarshal.AsBytes("00010203040506070809" + @@ -2163,11 +2170,11 @@ internal static string UInt32ToDecStr(uint value) internal static string UInt32ToDecStrForKnownSmallNumber(uint value) { Debug.Assert(value < SmallNumberCacheLength); - return s_smallNumberCache[value] ?? CreateAndCacheString(value); + return SmallNumberCache.Value[value] ?? CreateAndCacheString(value); [MethodImpl(MethodImplOptions.NoInlining)] // keep rare usage out of fast path static string CreateAndCacheString(uint value) => - s_smallNumberCache[value] = UInt32ToDecStr_NoSmallNumberCheck(value); + SmallNumberCache.Value[value] = UInt32ToDecStr_NoSmallNumberCheck(value); } private static unsafe string UInt32ToDecStr_NoSmallNumberCheck(uint value) From bd2d90cc6accd8473313ad81c7865612ce35acf0 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Aug 2026 18:52:13 -0700 Subject: [PATCH 2/4] Use RVA data for Number format patterns Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/System/Number.Formatting.Common.cs | 137 ++++++++++++------ 1 file changed, 91 insertions(+), 46 deletions(-) diff --git a/src/libraries/Common/src/System/Number.Formatting.Common.cs b/src/libraries/Common/src/System/Number.Formatting.Common.cs index 8a5a9397adcff8..a10a111a0ed270 100644 --- a/src/libraries/Common/src/System/Number.Formatting.Common.cs +++ b/src/libraries/Common/src/System/Number.Formatting.Common.cs @@ -17,48 +17,92 @@ internal static partial class Number private const int DefaultPrecisionExponentialFormat = 6; private const int MaxUInt32DecDigits = 10; - private const string PosNumberFormat = "#"; - private static class CurrencyFormats + private static ReadOnlySpan GetCurrencyFormat(bool isNegative, int index) { - internal static readonly string[] Positive = - [ - "$#", "#$", "$ #", "# $" - ]; - - internal static readonly string[] Negative = - [ - "($#)", "-$#", "$-#", "$#-", - "(#$)", "-#$", "#-$", "#$-", - "-# $", "-$ #", "# $-", "$ #-", - "$ -#", "#- $", "($ #)", "(# $)", - "$- #" - ]; + if (isNegative) + { + return index switch + { + 0 => "($#)"u8, + 1 => "-$#"u8, + 2 => "$-#"u8, + 3 => "$#-"u8, + 4 => "(#$)"u8, + 5 => "-#$"u8, + 6 => "#-$"u8, + 7 => "#$-"u8, + 8 => "-# $"u8, + 9 => "-$ #"u8, + 10 => "# $-"u8, + 11 => "$ #-"u8, + 12 => "$ -#"u8, + 13 => "#- $"u8, + 14 => "($ #)"u8, + 15 => "(# $)"u8, + 16 => "$- #"u8, + _ => throw new UnreachableException(), + }; + } + + return index switch + { + 0 => "$#"u8, + 1 => "#$"u8, + 2 => "$ #"u8, + 3 => "# $"u8, + _ => throw new UnreachableException(), + }; } - private static class PercentFormats + private static ReadOnlySpan GetPercentFormat(bool isNegative, int index) { - internal static readonly string[] Positive = - [ - "# %", "#%", "%#", "% #" - ]; - - internal static readonly string[] Negative = - [ - "-# %", "-#%", "-%#", - "%-#", "%#-", - "#-%", "#%-", - "-% #", "# %-", "% #-", - "% -#", "#- %" - ]; + if (isNegative) + { + return index switch + { + 0 => "-# %"u8, + 1 => "-#%"u8, + 2 => "-%#"u8, + 3 => "%-#"u8, + 4 => "%#-"u8, + 5 => "#-%"u8, + 6 => "#%-"u8, + 7 => "-% #"u8, + 8 => "# %-"u8, + 9 => "% #-"u8, + 10 => "% -#"u8, + 11 => "#- %"u8, + _ => throw new UnreachableException(), + }; + } + + return index switch + { + 0 => "# %"u8, + 1 => "#%"u8, + 2 => "%#"u8, + 3 => "% #"u8, + _ => throw new UnreachableException(), + }; } - private static class NumberFormats + private static ReadOnlySpan GetNumberFormat(bool isNegative, int index) { - internal static readonly string[] Negative = - [ - "(#)", "-#", "- #", "#-", "# -", - ]; + if (!isNegative) + { + return "#"u8; + } + + return index switch + { + 0 => "(#)"u8, + 1 => "-#"u8, + 2 => "- #"u8, + 3 => "#-"u8, + 4 => "# -"u8, + _ => throw new UnreachableException(), + }; } internal static char ParseFormatSpecifier(ReadOnlySpan format, out int digits) @@ -732,12 +776,13 @@ private static unsafe void FormatCurrency(ref ValueListBuilder vlb { Debug.Assert(sizeof(TChar) is sizeof(char) or sizeof(byte)); - string fmt = number.IsNegative ? - CurrencyFormats.Negative[info.CurrencyNegativePattern] : - CurrencyFormats.Positive[info.CurrencyPositivePattern]; + ReadOnlySpan fmt = GetCurrencyFormat( + number.IsNegative, + number.IsNegative ? info.CurrencyNegativePattern : info.CurrencyPositivePattern); - foreach (char ch in fmt) + foreach (byte value in fmt) { + char ch = (char)value; switch (ch) { case '#': @@ -902,12 +947,11 @@ private static unsafe void FormatNumber(ref ValueListBuilder vlb, { Debug.Assert(sizeof(TChar) is sizeof(char) or sizeof(byte)); - string fmt = number.IsNegative ? - NumberFormats.Negative[info.NumberNegativePattern] : - PosNumberFormat; + ReadOnlySpan fmt = GetNumberFormat(number.IsNegative, info.NumberNegativePattern); - foreach (char ch in fmt) + foreach (byte value in fmt) { + char ch = (char)value; switch (ch) { case '#': @@ -1029,12 +1073,13 @@ private static unsafe void FormatPercent(ref ValueListBuilder vlb, { Debug.Assert(sizeof(TChar) is sizeof(char) or sizeof(byte)); - string fmt = number.IsNegative ? - PercentFormats.Negative[info.PercentNegativePattern] : - PercentFormats.Positive[info.PercentPositivePattern]; + ReadOnlySpan fmt = GetPercentFormat( + number.IsNegative, + number.IsNegative ? info.PercentNegativePattern : info.PercentPositivePattern); - foreach (char ch in fmt) + foreach (byte value in fmt) { + char ch = (char)value; switch (ch) { case '#': From 49521e5d95a6b7280d3d83c484578be5aac99900 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Aug 2026 21:03:12 -0700 Subject: [PATCH 3/4] Use byte format pattern values directly Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/System/Number.Formatting.Common.cs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/src/System/Number.Formatting.Common.cs b/src/libraries/Common/src/System/Number.Formatting.Common.cs index a10a111a0ed270..7c492e0a08defa 100644 --- a/src/libraries/Common/src/System/Number.Formatting.Common.cs +++ b/src/libraries/Common/src/System/Number.Formatting.Common.cs @@ -780,20 +780,19 @@ private static unsafe void FormatCurrency(ref ValueListBuilder vlb number.IsNegative, number.IsNegative ? info.CurrencyNegativePattern : info.CurrencyPositivePattern); - foreach (byte value in fmt) + foreach (byte ch in fmt) { - char ch = (char)value; switch (ch) { - case '#': + case (byte)'#': FormatFixed(ref vlb, ref number, nMaxDigits, info.CurrencyGroupSizes(), info.CurrencyDecimalSeparatorTChar(), info.CurrencyGroupSeparatorTChar()); break; - case '-': + case (byte)'-': vlb.Append(info.NegativeSignTChar()); break; - case '$': + case (byte)'$': vlb.Append(info.CurrencySymbolTChar()); break; @@ -949,16 +948,15 @@ private static unsafe void FormatNumber(ref ValueListBuilder vlb, ReadOnlySpan fmt = GetNumberFormat(number.IsNegative, info.NumberNegativePattern); - foreach (byte value in fmt) + foreach (byte ch in fmt) { - char ch = (char)value; switch (ch) { - case '#': + case (byte)'#': FormatFixed(ref vlb, ref number, nMaxDigits, info.NumberGroupSizes(), info.NumberDecimalSeparatorTChar(), info.NumberGroupSeparatorTChar()); break; - case '-': + case (byte)'-': vlb.Append(info.NegativeSignTChar()); break; @@ -1077,20 +1075,19 @@ private static unsafe void FormatPercent(ref ValueListBuilder vlb, number.IsNegative, number.IsNegative ? info.PercentNegativePattern : info.PercentPositivePattern); - foreach (byte value in fmt) + foreach (byte ch in fmt) { - char ch = (char)value; switch (ch) { - case '#': + case (byte)'#': FormatFixed(ref vlb, ref number, nMaxDigits, info.PercentGroupSizes(), info.PercentDecimalSeparatorTChar(), info.PercentGroupSeparatorTChar()); break; - case '-': + case (byte)'-': vlb.Append(info.NegativeSignTChar()); break; - case '%': + case (byte)'%': vlb.Append(info.PercentSymbolTChar()); break; From f8aa4ae71b7218ddbd9944f4231cc251308f7f60 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Aug 2026 22:10:38 -0700 Subject: [PATCH 4/4] Eliminate sqrt coefficient bounds checks Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs index cb11c1aeeb6254..572d55dd9326f8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.DiyFp128Sqrt.cs @@ -574,7 +574,7 @@ private static DiyFp128 DiyFp128Sqrt(DiyFp128 x) fLo *= SqrtReciprocalTwoPow77; // The exponent parity is swapped into the table index so the reduced result lands in [1, 2). - int index = ((int)(msd >> (64 - SqrtNumFractionBits - 1)) & 0xFF) ^ (parity << SqrtNumFractionBits); + int index = (byte)(((int)(msd >> (64 - SqrtNumFractionBits - 1)) & 0xFF) ^ (parity << SqrtNumFractionBits)); ReadOnlySpan coefficientsAB = SqrtCoefficientsAB; ReadOnlySpan coefficientsC = SqrtCoefficientsC; int coefficientsABIndex = index * 2;