From a1bd90024064a55afc5a374ecd2ffc2d700e94d9 Mon Sep 17 00:00:00 2001 From: dotnet-maestro-bot Date: Mon, 12 Nov 2018 18:53:52 -0800 Subject: [PATCH] Update CoreClr, CoreFx, CoreFxOptimizationData, CoreSetup, ProjectNTfs, ProjectNTfsTestILC to preview-27113-01, preview.18563.1, master-20181113-0044, preview-27112-04, beta-27113-00, beta-27113-00, respectively (master) * Update CoreClr, CoreFx, CoreFxOptimizationData, CoreSetup, ProjectNTfs, ProjectNTfsTestILC to preview-27113-01, preview.18563.1, master-20181113-0044, preview-27112-04, beta-27113-00, beta-27113-00, respectively (master) * Removing the Utf8Parser and Utf8Formatter from System.Memory, now that it is in S.P.Corelib * Fixing the Math/MathF Min and Max tests --- eng/dependencies.props | 34 +- global.json | 2 +- src/System.Memory/src/System.Memory.csproj | 61 --- .../src/System/Number/Decimal.DecCalc.cs | 86 ---- .../System/Number/Number.FormatAndParse.cs | 487 ------------------ .../src/System/Number/Number.NumberBuffer.cs | 162 ------ src/System.Memory/src/System/Number/Number.cs | 63 --- .../tests/System/Math.cs | 62 +-- .../tests/System/MathF.netcoreapp.cs | 30 +- 9 files changed, 67 insertions(+), 920 deletions(-) delete mode 100644 src/System.Memory/src/System/Number/Decimal.DecCalc.cs delete mode 100644 src/System.Memory/src/System/Number/Number.FormatAndParse.cs delete mode 100644 src/System.Memory/src/System/Number/Number.NumberBuffer.cs delete mode 100644 src/System.Memory/src/System/Number/Number.cs diff --git a/eng/dependencies.props b/eng/dependencies.props index 36e4ea9ba22c..76b3b90155de 100644 --- a/eng/dependencies.props +++ b/eng/dependencies.props @@ -9,16 +9,16 @@ These ref versions are pulled from https://github.com/dotnet/versions. --> - 8f6558c7dc6384d0341d9bbe45741f0bb035c039 - 8f6558c7dc6384d0341d9bbe45741f0bb035c039 - 4107975d8819ff8690e655f89044e169c092f614 + 8112e1cc84cd60abc1854d5e057eb0085e0de9ab + 8112e1cc84cd60abc1854d5e057eb0085e0de9ab + 8112e1cc84cd60abc1854d5e057eb0085e0de9ab 96dc7805f5df4a70a55783964ce69dcd91bfca80 - 3d83d48dc99e1dc3b90a649c21c01c32a4c45f22 - 3d83d48dc99e1dc3b90a649c21c01c32a4c45f22 + 8112e1cc84cd60abc1854d5e057eb0085e0de9ab + 8112e1cc84cd60abc1854d5e057eb0085e0de9ab 8bd1ec5fac9f0eec34ff6b34b1d878b4359e02dd 9004703a1923e5c5582ceb8d79712df777412446 2f9cc14c9526d0f6c292b6ce49f57f4a59c05774 - 3d83d48dc99e1dc3b90a649c21c01c32a4c45f22 + 8112e1cc84cd60abc1854d5e057eb0085e0de9ab @@ -32,16 +32,16 @@ - preview.18562.3 - 3.0.0-preview.18562.3 - 3.0.0-preview-27112-03 - 3.0.0-preview-27112-03 - beta-27112-00 - beta-27112-00 - 1.0.0-beta-27112-00 - 3.0.0-preview-27109-05 - 3.0.0-preview-27109-05 - 3.0.0-preview-27109-05 + preview.18563.1 + 3.0.0-preview.18563.1 + 3.0.0-preview-27113-01 + 3.0.0-preview-27113-01 + beta-27113-00 + beta-27113-00 + 1.0.0-beta-27113-00 + 3.0.0-preview-27112-04 + 3.0.0-preview-27112-04 + 3.0.0-preview-27112-04 4.4.0 @@ -59,7 +59,7 @@ $(ProjectNTfsTestILCPackageVersion) $(ProjectNTfsTestILCPackageVersion) 2.0.0-rc-61101-17 - 99.99.99-master-20181112-0045 + 99.99.99-master-20181113-0044 diff --git a/global.json b/global.json index efab27c77c98..3562ffcf40e4 100644 --- a/global.json +++ b/global.json @@ -4,6 +4,6 @@ }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.18556.6", - "Microsoft.NET.Sdk.IL": "3.0.0-preview-27112-03" + "Microsoft.NET.Sdk.IL": "3.0.0-preview-27113-01" } } diff --git a/src/System.Memory/src/System.Memory.csproj b/src/System.Memory/src/System.Memory.csproj index c676d0b30d44..10ac9a1a74dc 100644 --- a/src/System.Memory/src/System.Memory.csproj +++ b/src/System.Memory/src/System.Memory.csproj @@ -27,67 +27,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/System.Memory/src/System/Number/Decimal.DecCalc.cs b/src/System.Memory/src/System/Number/Decimal.DecCalc.cs deleted file mode 100644 index 7592000372fa..000000000000 --- a/src/System.Memory/src/System/Number/Decimal.DecCalc.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// -// This code is copied almost verbatim from the same-named file in CoreRT with mechanical changes to make it build outside of CoreLib. -// - -namespace System -{ - internal static class DecimalDecCalc - { - private static uint D32DivMod1E9(uint hi32, ref uint lo32) - { - ulong n = (ulong)hi32 << 32 | lo32; - lo32 = (uint)(n / 1000000000); - return (uint)(n % 1000000000); - } - - // Performs the equivalent of: - // - // uint modulo = value % 1e9; - // value = value / 1e9; - // return modulo; - // - internal static uint DecDivMod1E9(ref MutableDecimal value) - { - return D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0, ref value.High), ref value.Mid), ref value.Low); - } - - internal static void DecAddInt32(ref MutableDecimal value, uint i) - { - if (D32AddCarry(ref value.Low, i)) - { - if (D32AddCarry(ref value.Mid, 1)) - { - D32AddCarry(ref value.High, 1); - } - } - } - - private static bool D32AddCarry(ref uint value, uint i) - { - uint v = value; - uint sum = v + i; - value = sum; - return (sum < v) || (sum < i); - } - - internal static void DecMul10(ref MutableDecimal value) - { - MutableDecimal d = value; - DecShiftLeft(ref value); - DecShiftLeft(ref value); - DecAdd(ref value, d); - DecShiftLeft(ref value); - } - - private static void DecShiftLeft(ref MutableDecimal value) - { - uint c0 = (value.Low & 0x80000000) != 0 ? 1u : 0u; - uint c1 = (value.Mid & 0x80000000) != 0 ? 1u : 0u; - value.Low = value.Low << 1; - value.Mid = (value.Mid << 1) | c0; - value.High = (value.High << 1) | c1; - } - - private static void DecAdd(ref MutableDecimal value, MutableDecimal d) - { - if (D32AddCarry(ref value.Low, d.Low)) - { - if (D32AddCarry(ref value.Mid, 1)) - { - D32AddCarry(ref value.High, 1); - } - } - - if (D32AddCarry(ref value.Mid, d.Mid)) - { - D32AddCarry(ref value.High, 1); - } - - D32AddCarry(ref value.High, d.High); - } - } -} diff --git a/src/System.Memory/src/System/Number/Number.FormatAndParse.cs b/src/System.Memory/src/System/Number/Number.FormatAndParse.cs deleted file mode 100644 index b510326b979c..000000000000 --- a/src/System.Memory/src/System/Number/Number.FormatAndParse.cs +++ /dev/null @@ -1,487 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Buffers.Text; -using Internal.Runtime.CompilerServices; - -// -// This code is copied almost verbatim from the same-named file in CoreRT with mechanical changes to Span-ify it. -// - -namespace System -{ - internal static partial class Number - { - public static unsafe bool NumberBufferToDecimal(ref NumberBuffer number, ref decimal value) - { - MutableDecimal d = new MutableDecimal(); - - byte* p = number.UnsafeDigits; - int e = number.Scale; - if (*p == 0) - { - // To avoid risking an app-compat issue with pre 4.5 (where some app was illegally using Reflection to examine the internal scale bits), we'll only force - // the scale to 0 if the scale was previously positive (previously, such cases were unparsable to a bug.) - if (e > 0) - { - e = 0; - } - } - else - { - if (e > DECIMAL_PRECISION) - return false; - - while (((e > 0) || ((*p != 0) && (e > -28))) && - ((d.High < 0x19999999) || ((d.High == 0x19999999) && - ((d.Mid < 0x99999999) || ((d.Mid == 0x99999999) && - ((d.Low < 0x99999999) || ((d.Low == 0x99999999) && - (*p <= '5')))))))) - { - DecimalDecCalc.DecMul10(ref d); - if (*p != 0) - DecimalDecCalc.DecAddInt32(ref d, (uint)(*p++ - '0')); - e--; - } - - if (*p++ >= '5') - { - bool round = true; - if ((*(p - 1) == '5') && ((*(p - 2) % 2) == 0)) - { - // Check if previous digit is even, only if the when we are unsure whether hows to do - // Banker's rounding. For digits > 5 we will be rounding up anyway. - int count = 20; // Look at the next 20 digits to check to round - while ((*p == '0') && (count != 0)) - { - p++; - count--; - } - if ((*p == '\0') || (count == 0)) - round = false;// Do nothing - } - - if (round) - { - DecimalDecCalc.DecAddInt32(ref d, 1); - if ((d.High | d.Mid | d.Low) == 0) - { - // If we got here, the magnitude portion overflowed and wrapped back to 0 as the magnitude was already at the MaxValue point: - // - // 79,228,162,514,264,337,593,543,950,335e+X - // - // Manually force it to the correct result: - // - // 7,922,816,251,426,433,759,354,395,034e+(X+1) - // - // This code path can be reached by trying to parse the following as a Decimal: - // - // 0.792281625142643375935439503355e28 - // - - d.High = 0x19999999; - d.Mid = 0x99999999; - d.Low = 0x9999999A; - e++; - } - } - } - } - - if (e > 0) - return false; // Rounding may have caused its own overflow. For example, parsing "0.792281625142643375935439503355e29" will get here. - - if (e <= -DECIMAL_PRECISION) - { - // Parsing a large scale zero can give you more precision than fits in the decimal. - // This should only happen for actual zeros or very small numbers that round to zero. - d.High = 0; - d.Low = 0; - d.Mid = 0; - d.Scale = DECIMAL_PRECISION - 1; - } - else - { - d.Scale = -e; - } - d.IsNegative = number.IsNegative; - - value = Unsafe.As(ref d); - return true; - } - - public static void DecimalToNumber(decimal value, ref NumberBuffer number) - { - ref MutableDecimal d = ref Unsafe.As(ref value); - - Span buffer = number.Digits; - number.IsNegative = d.IsNegative; - number.Kind = NumberBufferKind.Decimal; - - int index = DECIMAL_PRECISION; - - // Starting from the least significant bits, carve off nine decimal digits at a time and string-ize them (using the end of the - // buffer as a scratch buffer.) - while (d.Mid != 0 | d.High != 0) - { - uint modulo1E9 = DecimalDecCalc.DecDivMod1E9(ref d); - for (int digitCount = 0; digitCount < 9; digitCount++) - { - buffer[--index] = (byte)(modulo1E9 % 10 + '0'); - modulo1E9 /= 10; - } - } - - // We've finally whittled the decimal down to uint.MaxValue or less. Write the remaining digits but make sure no leading zeros get written. - uint remainder = d.Low; - while (remainder != 0) - { - buffer[--index] = (byte)(remainder % 10 + '0'); - remainder /= 10; - } - - int i = DECIMAL_PRECISION - index; - number.Scale = i - d.Scale; - - // Move the result from the end of the buffer to the beginning where we need it. - Span dst = number.Digits; - int dstIndex = 0; - while (--i >= 0) - { - dst[dstIndex++] = buffer[index++]; - } - dst[dstIndex] = 0; - - number.CheckConsistency(); - } - - // - // get 32-bit integer from at most 9 digits - // - private static uint DigitsToInt(ReadOnlySpan digits, int count) - { - bool success = Utf8Parser.TryParse(digits.Slice(0, count), out uint value, out int bytesConsumed, 'D'); - Debug.Assert(success); // This is only called on the contents of a trusted Number structure. - return value; - } - - // - // helper to multiply two 32-bit uints - // - private static ulong Mul32x32To64(uint a, uint b) - { - return a * (ulong)b; - } - - // - // multiply two numbers in the internal integer representation - // - private static ulong Mul64Lossy(ulong a, ulong b, ref int pexp) - { - // it's ok to lose some precision here - Mul64 will be called - // at most twice during the conversion, so the error won't propagate - // to any of the 53 significant bits of the result - ulong val = Mul32x32To64((uint)(a >> 32), (uint)(b >> 32)) + - (Mul32x32To64((uint)(a >> 32), (uint)(b)) >> 32) + - (Mul32x32To64((uint)(a), (uint)(b >> 32)) >> 32); - - // normalize - if ((val & 0x8000000000000000) == 0) - { - val <<= 1; - pexp -= 1; - } - - return val; - } - - // - // precomputed tables with powers of 10. These allows us to do at most - // two Mul64 during the conversion. This is important not only - // for speed, but also for precision because of Mul64 computes with 1 bit error. - // - - private static readonly ulong[] s_rgval64Power10 = - { - // powers of 10 - /*1*/ 0xa000000000000000, - /*2*/ 0xc800000000000000, - /*3*/ 0xfa00000000000000, - /*4*/ 0x9c40000000000000, - /*5*/ 0xc350000000000000, - /*6*/ 0xf424000000000000, - /*7*/ 0x9896800000000000, - /*8*/ 0xbebc200000000000, - /*9*/ 0xee6b280000000000, - /*10*/ 0x9502f90000000000, - /*11*/ 0xba43b74000000000, - /*12*/ 0xe8d4a51000000000, - /*13*/ 0x9184e72a00000000, - /*14*/ 0xb5e620f480000000, - /*15*/ 0xe35fa931a0000000, - - // powers of 0.1 - /*1*/ 0xcccccccccccccccd, - /*2*/ 0xa3d70a3d70a3d70b, - /*3*/ 0x83126e978d4fdf3c, - /*4*/ 0xd1b71758e219652e, - /*5*/ 0xa7c5ac471b478425, - /*6*/ 0x8637bd05af6c69b7, - /*7*/ 0xd6bf94d5e57a42be, - /*8*/ 0xabcc77118461ceff, - /*9*/ 0x89705f4136b4a599, - /*10*/ 0xdbe6fecebdedd5c2, - /*11*/ 0xafebff0bcb24ab02, - /*12*/ 0x8cbccc096f5088cf, - /*13*/ 0xe12e13424bb40e18, - /*14*/ 0xb424dc35095cd813, - /*15*/ 0x901d7cf73ab0acdc, - }; - - private static readonly sbyte[] s_rgexp64Power10 = - { - // exponents for both powers of 10 and 0.1 - /*1*/ 4, - /*2*/ 7, - /*3*/ 10, - /*4*/ 14, - /*5*/ 17, - /*6*/ 20, - /*7*/ 24, - /*8*/ 27, - /*9*/ 30, - /*10*/ 34, - /*11*/ 37, - /*12*/ 40, - /*13*/ 44, - /*14*/ 47, - /*15*/ 50, - }; - - private static readonly ulong[] s_rgval64Power10By16 = - { - // powers of 10^16 - /*1*/ 0x8e1bc9bf04000000, - /*2*/ 0x9dc5ada82b70b59e, - /*3*/ 0xaf298d050e4395d6, - /*4*/ 0xc2781f49ffcfa6d4, - /*5*/ 0xd7e77a8f87daf7fa, - /*6*/ 0xefb3ab16c59b14a0, - /*7*/ 0x850fadc09923329c, - /*8*/ 0x93ba47c980e98cde, - /*9*/ 0xa402b9c5a8d3a6e6, - /*10*/ 0xb616a12b7fe617a8, - /*11*/ 0xca28a291859bbf90, - /*12*/ 0xe070f78d39275566, - /*13*/ 0xf92e0c3537826140, - /*14*/ 0x8a5296ffe33cc92c, - /*15*/ 0x9991a6f3d6bf1762, - /*16*/ 0xaa7eebfb9df9de8a, - /*17*/ 0xbd49d14aa79dbc7e, - /*18*/ 0xd226fc195c6a2f88, - /*19*/ 0xe950df20247c83f8, - /*20*/ 0x81842f29f2cce373, - /*21*/ 0x8fcac257558ee4e2, - - // powers of 0.1^16 - /*1*/ 0xe69594bec44de160, - /*2*/ 0xcfb11ead453994c3, - /*3*/ 0xbb127c53b17ec165, - /*4*/ 0xa87fea27a539e9b3, - /*5*/ 0x97c560ba6b0919b5, - /*6*/ 0x88b402f7fd7553ab, - /*7*/ 0xf64335bcf065d3a0, - /*8*/ 0xddd0467c64bce4c4, - /*9*/ 0xc7caba6e7c5382ed, - /*10*/ 0xb3f4e093db73a0b7, - /*11*/ 0xa21727db38cb0053, - /*12*/ 0x91ff83775423cc29, - /*13*/ 0x8380dea93da4bc82, - /*14*/ 0xece53cec4a314f00, - /*15*/ 0xd5605fcdcf32e217, - /*16*/ 0xc0314325637a1978, - /*17*/ 0xad1c8eab5ee43ba2, - /*18*/ 0x9becce62836ac5b0, - /*19*/ 0x8c71dcd9ba0b495c, - /*20*/ 0xfd00b89747823938, - /*21*/ 0xe3e27a444d8d991a, - }; - - private static readonly short[] s_rgexp64Power10By16 = - { - // exponents for both powers of 10^16 and 0.1^16 - /*1*/ 54, - /*2*/ 107, - /*3*/ 160, - /*4*/ 213, - /*5*/ 266, - /*6*/ 319, - /*7*/ 373, - /*8*/ 426, - /*9*/ 479, - /*10*/ 532, - /*11*/ 585, - /*12*/ 638, - /*13*/ 691, - /*14*/ 745, - /*15*/ 798, - /*16*/ 851, - /*17*/ 904, - /*18*/ 957, - /*19*/ 1010, - /*20*/ 1064, - /*21*/ 1117, - }; - - private static int abs(int value) - { - if (value < 0) - return -value; - return value; - } - - public static unsafe double NumberBufferToDouble(ref NumberBuffer number) - { - ulong val; - int exp; - ReadOnlySpan src = number.Digits; - int remaining; - int total; - int count; - int scale; - int absscale; - int index; - int srcIndex = 0; - - total = number.NumDigits; - remaining = total; - - // skip the leading zeros - while (src[srcIndex] == '0') - { - remaining--; - srcIndex++; - } - - if (remaining == 0) - return number.IsNegative ? -0.0 : 0.0; - - count = Math.Min(remaining, 9); - remaining -= count; - val = DigitsToInt(src, count); - - if (remaining > 0) - { - count = Math.Min(remaining, 9); - remaining -= count; - - // get the denormalized power of 10 - uint mult = (uint)(s_rgval64Power10[count - 1] >> (64 - s_rgexp64Power10[count - 1])); - val = Mul32x32To64((uint)val, mult) + DigitsToInt(src.Slice(9), count); - } - - scale = number.Scale - (total - remaining); - absscale = abs(scale); - if (absscale >= 22 * 16) - { - // overflow / underflow - ulong result = (scale > 0) ? 0x7FF0000000000000 : 0ul; - if (number.IsNegative) - result |= 0x8000000000000000; - return *(double*)&result; - } - - exp = 64; - - // normalize the mantissa - if ((val & 0xFFFFFFFF00000000) == 0) - { val <<= 32; exp -= 32; } - if ((val & 0xFFFF000000000000) == 0) - { val <<= 16; exp -= 16; } - if ((val & 0xFF00000000000000) == 0) - { val <<= 8; exp -= 8; } - if ((val & 0xF000000000000000) == 0) - { val <<= 4; exp -= 4; } - if ((val & 0xC000000000000000) == 0) - { val <<= 2; exp -= 2; } - if ((val & 0x8000000000000000) == 0) - { val <<= 1; exp -= 1; } - - index = absscale & 15; - if (index != 0) - { - int multexp = s_rgexp64Power10[index - 1]; - // the exponents are shared between the inverted and regular table - exp += (scale < 0) ? (-multexp + 1) : multexp; - - ulong multval = s_rgval64Power10[index + ((scale < 0) ? 15 : 0) - 1]; - val = Mul64Lossy(val, multval, ref exp); - } - - index = absscale >> 4; - if (index != 0) - { - int multexp = s_rgexp64Power10By16[index - 1]; - // the exponents are shared between the inverted and regular table - exp += (scale < 0) ? (-multexp + 1) : multexp; - - ulong multval = s_rgval64Power10By16[index + ((scale < 0) ? 21 : 0) - 1]; - val = Mul64Lossy(val, multval, ref exp); - } - - // round & scale down - if (((int)val & (1 << 10)) != 0) - { - // IEEE round to even - ulong tmp = val + ((1 << 10) - 1) + (ulong)(((int)val >> 11) & 1); - if (tmp < val) - { - // overflow - tmp = (tmp >> 1) | 0x8000000000000000; - exp += 1; - } - val = tmp; - } - - // return the exponent to a biased state - exp += 0x3FE; - - // handle overflow, underflow, "Epsilon - 1/2 Epsilon", denormalized, and the normal case - if (exp <= 0) - { - if (exp == -52 && (val >= 0x8000000000000058)) - { - // round X where {Epsilon > X >= 2.470328229206232730000000E-324} up to Epsilon (instead of down to zero) - val = 0x0000000000000001; - } - else if (exp <= -52) - { - // underflow - val = 0; - } - else - { - // denormalized - val >>= (-exp + 11 + 1); - } - } - else if (exp >= 0x7FF) - { - // overflow - val = 0x7FF0000000000000; - } - else - { - // normal postive exponent case - val = ((ulong)exp << 52) + ((val >> 11) & 0x000FFFFFFFFFFFFF); - } - - if (number.IsNegative) - val |= 0x8000000000000000; - - return *(double*)&val; - } - } -} diff --git a/src/System.Memory/src/System/Number/Number.NumberBuffer.cs b/src/System.Memory/src/System/Number/Number.NumberBuffer.cs deleted file mode 100644 index e21ae1adcb89..000000000000 --- a/src/System.Memory/src/System/Number/Number.NumberBuffer.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Text; -using System.Runtime.InteropServices; -using Internal.Runtime.CompilerServices; - -namespace System -{ - // - // This is a port of the Number/NumberBuffer structure from CoreRT (which in turn was a C#-ized port of the NUMBER struct inside CoreCLR.) - // We use this as the more heavyweight data types such as Decimal and floats. That is, we use Number as a common representation of these types - // and thus share the formatting/parsing routines among them. - // - // This structure can only be stack-allocated as it returns a reference to a fixed-length array inside. - // - [StructLayout(LayoutKind.Sequential)] - internal ref struct NumberBuffer - { - // The Scale is the index of the implied decimal point. Can be negative or beyond the end of the NUL terminator. Examples: - // - // 123.45 => "12345", Scale = 3 - // 0.005 => "5", Scale = -2 - // 1000.00 => "1", Scale = 4 (though it's not guaranteed that it won't be "1000, Scale=0" instead.) - // 0 => "", Scale = 0 - // 3m => "3", Scale = 1 - // 3.00m => "300", Scale = 1 (this is important: trailing zeroes actually matter in Decimal) - // - public int Scale; - public NumberBufferKind Kind; - public bool IsNegative; - - public unsafe Span Digits => new Span(Unsafe.AsPointer(ref _b0), BufferSize); - - public unsafe byte* UnsafeDigits => (byte*)Unsafe.AsPointer(ref _b0); - - public int NumDigits => Digits.IndexOf(0); - - [Conditional("DEBUG")] - public void CheckConsistency() - { -#if DEBUG - Span digits = Digits; - - Debug.Assert(digits[0] != '0', "Leading zeros should never be stored in a Number"); - - int numDigits; - for (numDigits = 0; numDigits < BufferSize; numDigits++) - { - byte digit = digits[numDigits]; - if (digit == 0) - break; - - Debug.Assert(digit >= '0' && digit <= '9', "Unexpected character found in Number"); - } - - Debug.Assert(numDigits < BufferSize, "NUL terminator not found in Number"); -#endif // DEBUG - } - - // - // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it works. - // - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - sb.Append('['); - sb.Append('"'); - Span digits = Digits; - for (int i = 0; i < BufferSize; i++) - { - byte digit = digits[i]; - if (digit == 0) - break; - sb.Append((char)digit); - } - sb.Append('"'); - sb.Append(", Scale = " + Scale); - sb.Append(", IsNegative = " + IsNegative); - sb.Append(']'); - return sb.ToString(); - } - - public const int BufferSize = 50 + 1; // Matches https://github.com/dotnet/coreclr/blob/097e68658c5249eaefff33bd92b044e9ba22c819/src/classlibnative/bcltype/number.h#L15 - - // - // 50+1 bytes of ASCII digits ('0'..'9'). (Not using "fixed byte[]" as this breaks the VS debugging experience.) - // That's enough room to store the worst case Decimal and double. - // - // A NUL terminator (not to be confused with '0') marks the end of the digits. - // - // Leading zeroes are never stored, even if the entire number is zero. - // - // Trailing zeroes after the decimal point *are* stored. This is important for System.Decimal - // as trailing zeroes are significant in Decimal: - // - // decimal d1 = 1m; => d1.ToString("G") emits "1" - // decimal d2 = 1.00m; => d1.ToStirng("G") emits "1.00" - // - private byte _b0; - private byte _b1; - private byte _b2; - private byte _b3; - private byte _b4; - private byte _b5; - private byte _b6; - private byte _b7; - private byte _b8; - private byte _b9; - private byte _b10; - private byte _b11; - private byte _b12; - private byte _b13; - private byte _b14; - private byte _b15; - private byte _b16; - private byte _b17; - private byte _b18; - private byte _b19; - private byte _b20; - private byte _b21; - private byte _b22; - private byte _b23; - private byte _b24; - private byte _b25; - private byte _b26; - private byte _b27; - private byte _b28; - private byte _b29; - private byte _b30; - private byte _b31; - private byte _b32; - private byte _b33; - private byte _b34; - private byte _b35; - private byte _b36; - private byte _b37; - private byte _b38; - private byte _b39; - private byte _b40; - private byte _b41; - private byte _b42; - private byte _b43; - private byte _b44; - private byte _b45; - private byte _b46; - private byte _b47; - private byte _b48; - private byte _b49; - private byte _b50; - } - - internal enum NumberBufferKind : byte - { - Unknown, - Integer, - Decimal, - Double - } -} diff --git a/src/System.Memory/src/System/Number/Number.cs b/src/System.Memory/src/System/Number/Number.cs deleted file mode 100644 index 395a02d4b8df..000000000000 --- a/src/System.Memory/src/System/Number/Number.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// -// This code is copied almost verbatim from the same-named file in CoreRT with mechanical changes to Span-ify it. -// - -namespace System -{ - internal static partial class Number - { - internal const int DECIMAL_PRECISION = 29; - - // - // This method is copied directly from CoreRT (which is in turn a C#-ized version of the CoreCLR C++ code.) - // - public static void RoundNumber(ref NumberBuffer number, int pos) - { - number.CheckConsistency(); - - Span digits = number.Digits; - - int i = 0; - while (i < pos && digits[i] != 0) - i++; - - if (i == pos && digits[i] >= (byte)'5') - { - while (i > 0 && digits[i - 1] == (byte)'9') - i--; - - if (i > 0) - { - digits[i - 1]++; - } - else - { - number.Scale++; - digits[0] = (byte)'1'; - i = 1; - } - } - else - { - while (i > 0 && digits[i - 1] == (byte)'0') - i--; - } - if (i == 0) - { - number.Scale = 0; - - if (number.Kind == NumberBufferKind.Integer) - { - number.IsNegative = false; - } - } - digits[i] = 0; - - number.CheckConsistency(); - } - } -} diff --git a/src/System.Runtime.Extensions/tests/System/Math.cs b/src/System.Runtime.Extensions/tests/System/Math.cs index 0ee3b2aa3e59..7216267d1104 100644 --- a/src/System.Runtime.Extensions/tests/System/Math.cs +++ b/src/System.Runtime.Extensions/tests/System/Math.cs @@ -1062,14 +1062,15 @@ public static void Max_Decimal() Assert.Equal(decimal.MaxValue, Math.Max(decimal.MinValue, decimal.MaxValue)); } - [Fact] - public static void Max_Double() + [Theory] + [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] + [InlineData(double.MinValue, double.MaxValue, double.MaxValue)] + [InlineData(double.NaN, double.NaN, double.NaN)] + [InlineData(3.0, -2.0, 3.0)] + [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity)] + public static void Max_Double(double x, double y, double expectedResult) { - Assert.Equal(3.0, Math.Max(3.0, -2.0)); - Assert.Equal(double.MaxValue, Math.Max(double.MinValue, double.MaxValue)); - Assert.Equal(double.PositiveInfinity, Math.Max(double.NegativeInfinity, double.PositiveInfinity)); - Assert.Equal(double.NaN, Math.Max(double.PositiveInfinity, double.NaN)); - Assert.Equal(double.NaN, Math.Max(double.NaN, double.NaN)); + AssertEqual(expectedResult, Math.Max(x, y), 0.0); } [Fact] @@ -1100,14 +1101,15 @@ public static void Max_SByte() Assert.Equal(sbyte.MaxValue, Math.Max(sbyte.MinValue, sbyte.MaxValue)); } - [Fact] - public static void Max_Single() + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(3.0f, -2.0f, 3.0f)] + [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] + public static void Max_Single(float x, float y, float expectedResult) { - Assert.Equal(3.0f, Math.Max(3.0f, -2.0f)); - Assert.Equal(float.MaxValue, Math.Max(float.MinValue, float.MaxValue)); - Assert.Equal(float.PositiveInfinity, Math.Max(float.NegativeInfinity, float.PositiveInfinity)); - Assert.Equal(float.NaN, Math.Max(float.PositiveInfinity, float.NaN)); - Assert.Equal(float.NaN, Math.Max(float.NaN, float.NaN)); + AssertEqual(expectedResult, Math.Max(x, y), 0.0f); } [Fact] @@ -1145,14 +1147,15 @@ public static void Min_Decimal() Assert.Equal(decimal.MinValue, Math.Min(decimal.MinValue, decimal.MaxValue)); } - [Fact] - public static void Min_Double() + [Theory] + [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)] + [InlineData(double.MinValue, double.MaxValue, double.MinValue)] + [InlineData(double.NaN, double.NaN, double.NaN)] + [InlineData(3.0, -2.0, -2.0)] + [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity)] + public static void Min_Double(double x, double y, double expectedResult) { - Assert.Equal(-2.0, Math.Min(3.0, -2.0)); - Assert.Equal(double.MinValue, Math.Min(double.MinValue, double.MaxValue)); - Assert.Equal(double.NegativeInfinity, Math.Min(double.NegativeInfinity, double.PositiveInfinity)); - Assert.Equal(double.NaN, Math.Min(double.NegativeInfinity, double.NaN)); - Assert.Equal(double.NaN, Math.Min(double.NaN, double.NaN)); + AssertEqual(expectedResult, Math.Min(x, y), 0.0); } [Fact] @@ -1183,14 +1186,15 @@ public static void Min_SByte() Assert.Equal(sbyte.MinValue, Math.Min(sbyte.MinValue, sbyte.MaxValue)); } - [Fact] - public static void Min_Single() - { - Assert.Equal(-2.0f, Math.Min(3.0f, -2.0f)); - Assert.Equal(float.MinValue, Math.Min(float.MinValue, float.MaxValue)); - Assert.Equal(float.NegativeInfinity, Math.Min(float.NegativeInfinity, float.PositiveInfinity)); - Assert.Equal(float.NaN, Math.Min(float.NegativeInfinity, float.NaN)); - Assert.Equal(float.NaN, Math.Min(float.NaN, float.NaN)); + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MinValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(3.0, -2.0, -2.0)] + [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] + public static void Min_Single(float x, float y, float expectedResult) + { + AssertEqual(expectedResult, Math.Min(x, y), 0.0f); } [Fact] diff --git a/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs index 82e97a103121..ac71ad94fa03 100644 --- a/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs +++ b/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs @@ -914,24 +914,26 @@ public static void Log10(float value, float expectedResult, float allowedVarianc AssertEqual(expectedResult, MathF.Log10(value), allowedVariance); } - [Fact] - public static void Max() + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(3.0f, -2.0f, 3.0f)] + [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] + public static void Max(float x, float y, float expectedResult) { - Assert.Equal(3.0f, MathF.Max(3.0f, -2.0f)); - Assert.Equal(float.MaxValue, MathF.Max(float.MinValue, float.MaxValue)); - Assert.Equal(float.PositiveInfinity, MathF.Max(float.NegativeInfinity, float.PositiveInfinity)); - Assert.Equal(float.NaN, MathF.Max(float.PositiveInfinity, float.NaN)); - Assert.Equal(float.NaN, MathF.Max(float.NaN, float.NaN)); + AssertEqual(expectedResult, Math.Max(x, y), 0.0f); } - [Fact] - public static void Min() + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MinValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(3.0, -2.0, -2.0)] + [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] + public static void Min(float x, float y, float expectedResult) { - Assert.Equal(-2.0f, MathF.Min(3.0f, -2.0f)); - Assert.Equal(float.MinValue, MathF.Min(float.MinValue, float.MaxValue)); - Assert.Equal(float.NegativeInfinity, MathF.Min(float.NegativeInfinity, float.PositiveInfinity)); - Assert.Equal(float.NaN, MathF.Min(float.NegativeInfinity, float.NaN)); - Assert.Equal(float.NaN, MathF.Min(float.NaN, float.NaN)); + AssertEqual(expectedResult, Math.Min(x, y), 0.0f); } [Theory]