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 38a752c6810ffe..e22a12d24f6440 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -268,11 +268,11 @@ internal static partial class Number 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 readonly string?[] s_smallNumberCache = new string[SmallNumberCacheLength]; // Optimizations using "TwoDigits" inspired by: // https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c/ - private static readonly byte[] TwoDigitsCharsAsBytes = + private static ReadOnlySpan TwoDigitsCharsAsBytes => MemoryMarshal.AsBytes("00010203040506070809" + "10111213141516171819" + "20212223242526272829" + @@ -282,9 +282,9 @@ internal static partial class Number "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + - "90919293949596979899").ToArray(); - private static readonly byte[] TwoDigitsBytes = - ("00010203040506070809"u8 + + "90919293949596979899"); + private static ReadOnlySpan TwoDigitsBytes => + "00010203040506070809"u8 + "10111213141516171819"u8 + "20212223242526272829"u8 + "30313233343536373839"u8 + @@ -293,7 +293,7 @@ internal static partial class Number "60616263646566676869"u8 + "70717273747576777879"u8 + "80818283848586878889"u8 + - "90919293949596979899"u8).ToArray(); + "90919293949596979899"u8; public static unsafe string FormatDecimal(decimal value, ReadOnlySpan format, NumberFormatInfo info) { @@ -387,9 +387,8 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci int maxDigits = precision; - switch (fmt) + switch (fmt | 0x20) { - case 'C': case 'c': { // The currency format uses the precision specifier to indicate the number of @@ -404,7 +403,6 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci break; } - case 'E': case 'e': { // The exponential format uses the precision specifier to indicate the number of @@ -423,9 +421,7 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci break; } - case 'F': case 'f': - case 'N': case 'n': { // The fixed-point and number formats use the precision specifier to indicate the number @@ -440,7 +436,6 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci break; } - case 'G': case 'g': { // The general format uses the precision specifier to indicate the number of significant @@ -457,7 +452,6 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci break; } - case 'P': case 'p': { // The percent format uses the precision specifier to indicate the number of @@ -476,7 +470,6 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci break; } - case 'R': case 'r': { // The roundtrip format ignores the precision specifier and always returns the shortest @@ -1579,7 +1572,7 @@ internal static unsafe void WriteTwoDigits(uint value, TChar* ptr) where Unsafe.CopyBlockUnaligned( ref *(byte*)ptr, - ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes), (uint)sizeof(TChar) * 2 * value), + ref Unsafe.Add(ref MemoryMarshal.GetReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes), (uint)sizeof(TChar) * 2 * value), (uint)sizeof(TChar) * 2); } @@ -1595,7 +1588,7 @@ internal static unsafe void WriteFourDigits(uint value, TChar* ptr) where (value, uint remainder) = Math.DivRem(value, 100); - ref byte charsArray = ref MemoryMarshal.GetArrayDataReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes); + ref byte charsArray = ref MemoryMarshal.GetReference(typeof(TChar) == typeof(char) ? TwoDigitsCharsAsBytes : TwoDigitsBytes); Unsafe.CopyBlockUnaligned( ref *(byte*)ptr, @@ -1677,7 +1670,7 @@ internal static unsafe void WriteDigits(uint value, TChar* ptr, int count return bufferEnd; } - internal static unsafe string UInt32ToDecStr(uint value) + internal static string UInt32ToDecStr(uint value) { // For small numbers, consult a lazily-populated cache. if (value < SmallNumberCacheLength) @@ -2540,102 +2533,6 @@ private static unsafe bool TryUInt128ToDecStr(UInt128 value, int digits, return false; } - private static ulong ExtractFractionAndBiasedExponent(double value, out int exponent) - { - ulong bits = BitConverter.DoubleToUInt64Bits(value); - ulong fraction = (bits & 0xFFFFFFFFFFFFF); - exponent = ((int)(bits >> 52) & 0x7FF); - - if (exponent != 0) - { - // For normalized value, according to https://en.wikipedia.org/wiki/Double-precision_floating-point_format - // value = 1.fraction * 2^(exp - 1023) - // = (1 + mantissa / 2^52) * 2^(exp - 1023) - // = (2^52 + mantissa) * 2^(exp - 1023 - 52) - // - // So f = (2^52 + mantissa), e = exp - 1075; - - fraction |= (1UL << 52); - exponent -= 1075; - } - else - { - // For denormalized value, according to https://en.wikipedia.org/wiki/Double-precision_floating-point_format - // value = 0.fraction * 2^(1 - 1023) - // = (mantissa / 2^52) * 2^(-1022) - // = mantissa * 2^(-1022 - 52) - // = mantissa * 2^(-1074) - // So f = mantissa, e = -1074 - exponent = -1074; - } - - return fraction; - } - - private static ushort ExtractFractionAndBiasedExponent(Half value, out int exponent) - { - ushort bits = BitConverter.HalfToUInt16Bits(value); - ushort fraction = (ushort)(bits & 0x3FF); - exponent = ((int)(bits >> 10) & 0x1F); - - if (exponent != 0) - { - // For normalized value, according to https://en.wikipedia.org/wiki/Half-precision_floating-point_format - // value = 1.fraction * 2^(exp - 15) - // = (1 + mantissa / 2^10) * 2^(exp - 15) - // = (2^10 + mantissa) * 2^(exp - 15 - 10) - // - // So f = (2^10 + mantissa), e = exp - 25; - - fraction |= (ushort)(1U << 10); - exponent -= 25; - } - else - { - // For denormalized value, according to https://en.wikipedia.org/wiki/Half-precision_floating-point_format - // value = 0.fraction * 2^(1 - 15) - // = (mantissa / 2^10) * 2^(-14) - // = mantissa * 2^(-14 - 10) - // = mantissa * 2^(-24) - // So f = mantissa, e = -24 - exponent = -24; - } - - return fraction; - } - - private static uint ExtractFractionAndBiasedExponent(float value, out int exponent) - { - uint bits = BitConverter.SingleToUInt32Bits(value); - uint fraction = (bits & 0x7FFFFF); - exponent = ((int)(bits >> 23) & 0xFF); - - if (exponent != 0) - { - // For normalized value, according to https://en.wikipedia.org/wiki/Single-precision_floating-point_format - // value = 1.fraction * 2^(exp - 127) - // = (1 + mantissa / 2^23) * 2^(exp - 127) - // = (2^23 + mantissa) * 2^(exp - 127 - 23) - // - // So f = (2^23 + mantissa), e = exp - 150; - - fraction |= (1U << 23); - exponent -= 150; - } - else - { - // For denormalized value, according to https://en.wikipedia.org/wiki/Single-precision_floating-point_format - // value = 0.fraction * 2^(1 - 127) - // = (mantissa / 2^23) * 2^(-126) - // = mantissa * 2^(-126 - 23) - // = mantissa * 2^(-149) - // So f = mantissa, e = -149 - exponent = -149; - } - - return fraction; - } - private static ulong ExtractFractionAndBiasedExponent(TNumber value, out int exponent) where TNumber : unmanaged, IBinaryFloatParseAndFormatInfo {