Porting NumberToDouble to managed code. (#20080)
authorTanner Gooding <tagoo@outlook.com>
Sat, 22 Sep 2018 13:43:30 +0000 (06:43 -0700)
committerGitHub <noreply@github.com>
Sat, 22 Sep 2018 13:43:30 +0000 (06:43 -0700)
* Porting NumberToDouble to managed code.

* Deleting bcltype/number.cpp and bcltype/number.h

* Fixing NumberToDouble to call Int64BitsToDouble, rather than DoubleToInt64Bits

* Some minor code cleanup in NumberToDouble for better readability.

* Some additional code cleanup in the Number.NumberToDouble.cs code

src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
src/System.Private.CoreLib/shared/System/Number.NumberBuffer.cs
src/System.Private.CoreLib/shared/System/Number.NumberToDouble.cs [new file with mode: 0644]
src/System.Private.CoreLib/src/System/Number.CoreCLR.cs [deleted file]
src/classlibnative/bcltype/CMakeLists.txt
src/classlibnative/bcltype/number.cpp [deleted file]
src/classlibnative/bcltype/number.h [deleted file]
src/vm/ecalllist.h
src/vm/mscorlib.cpp

index a6abde3..f7064c8 100644 (file)
     <Compile Include="$(BclSourcesRoot)\System\MathF.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\mda.cs" />
     <Compile Include="$(BclSourcesRoot)\System\MissingMemberException.CoreCLR.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Number.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\RtType.cs" />
     <Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />
     <Compile Include="$(BclSourcesRoot)\System\RuntimeHandles.cs" />
index af7493c..378fa08 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Number.Formatting.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Number.Grisu3.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Number.NumberBuffer.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Number.NumberToDouble.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Number.Parsing.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\NullReferenceException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\ObjectDisposedException.cs" />
index fe9eaf6..c4d5ba5 100644 (file)
@@ -3,14 +3,13 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
 using Internal.Runtime.CompilerServices;
 
 namespace System
 {
     internal static partial class Number
     {
-        private const int NumberMaxDigits = 50; // needs to == NUMBER_MAXDIGITS in coreclr's src/classlibnative/bcltype/number.h.
+        private const int NumberMaxDigits = 50;
 
         private const double Log10V2 = 0.30102999566398119521373889472449;
 
@@ -18,7 +17,7 @@ namespace System
         private const double DriftFactor = 0.69;
 
         [StructLayout(LayoutKind.Sequential, Pack = 1)]
-        internal unsafe ref struct NumberBuffer // needs to match layout of NUMBER in coreclr's src/classlibnative/bcltype/number.h
+        internal unsafe ref struct NumberBuffer
         {
             public int precision;                       //  0
             public int scale;                           //  4
@@ -35,7 +34,7 @@ namespace System
             private struct DigitsAndNullTerminator { }
         }
 
-        internal enum NumberBufferKind // needs to match NUMBER_KIND in coreclr's src/classlibnative/bcltype/number.h
+        internal enum NumberBufferKind
         {
             Unknown = 0,
             Integer = 1,
diff --git a/src/System.Private.CoreLib/shared/System/Number.NumberToDouble.cs b/src/System.Private.CoreLib/shared/System/Number.NumberToDouble.cs
new file mode 100644 (file)
index 0000000..4e4c5bc
--- /dev/null
@@ -0,0 +1,449 @@
+// 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;
+
+namespace System
+{
+    internal unsafe partial class Number
+    {
+        // 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_Pow10MantissaTable = new ulong[]
+        {
+            // powers of 10
+            0XA0000000_00000000,     // 1
+            0XC8000000_00000000,     // 2
+            0XFA000000_00000000,     // 3
+            0X9C400000_00000000,     // 4
+            0XC3500000_00000000,     // 5
+            0XF4240000_00000000,     // 6
+            0X98968000_00000000,     // 7
+            0XBEBC2000_00000000,     // 8
+            0XEE6B2800_00000000,     // 9
+            0X9502F900_00000000,     // 10
+            0XBA43B740_00000000,     // 11
+            0XE8D4A510_00000000,     // 12
+            0X9184E72A_00000000,     // 13
+            0XB5E620F4_80000000,     // 14
+            0XE35FA931_A0000000,     // 15
+
+            // powers of 0.1
+            0xCCCCCCCC_CCCCCCCD,     // 1
+            0xA3D70A3D_70A3D70B,     // 2
+            0x83126E97_8D4FDF3C,     // 3
+            0xD1B71758_E219652E,     // 4
+            0xA7C5AC47_1B478425,     // 5
+            0x8637BD05_AF6C69B7,     // 6
+            0xD6BF94D5_E57A42BE,     // 7
+            0xABCC7711_8461CEFF,     // 8
+            0x89705F41_36B4A599,     // 9
+            0xDBE6FECE_BDEDD5C2,     // 10
+            0xAFEBFF0B_CB24AB02,     // 11
+            0x8CBCCC09_6F5088CF,     // 12
+            0xE12E1342_4BB40E18,     // 13
+            0xB424DC35_095CD813,     // 14
+            0x901D7CF7_3AB0ACDC,     // 15
+        };
+
+        private static readonly short[] s_Pow10ExponentTable = new short[]
+        {
+            // exponents for both powers of 10 and 0.1
+            4,      // 1
+            7,      // 2
+            10,     // 3
+            14,     // 4
+            17,     // 5
+            20,     // 6
+            24,     // 7
+            27,     // 8
+            30,     // 9
+            34,     // 10
+            37,     // 11
+            40,     // 12
+            44,     // 13
+            47,     // 14
+            50,     // 15
+        };
+
+        private static readonly ulong[] s_Pow10By16MantissaTable = new ulong[]
+        {
+            // powers of 10^16
+            0x8E1BC9BF_04000000,     // 1
+            0x9DC5ADA8_2B70B59E,     // 2
+            0xAF298D05_0E4395D6,     // 3
+            0xC2781F49_FFCFA6D4,     // 4
+            0xD7E77A8F_87DAF7FA,     // 5
+            0xEFB3AB16_C59B14A0,     // 6
+            0x850FADC0_9923329C,     // 7
+            0x93BA47C9_80E98CDE,     // 8
+            0xA402B9C5_A8D3A6E6,     // 9
+            0xB616A12B_7FE617A8,     // 10
+            0xCA28A291_859BBF90,     // 11
+            0xE070F78D_39275566,     // 12
+            0xF92E0C35_37826140,     // 13
+            0x8A5296FF_E33CC92C,     // 14
+            0x9991A6F3_D6BF1762,     // 15
+            0xAA7EEBFB_9DF9DE8A,     // 16
+            0xBD49D14A_A79DBC7E,     // 17
+            0xD226FC19_5C6A2F88,     // 18
+            0xE950DF20_247C83F8,     // 19
+            0x81842F29_F2CCE373,     // 20
+            0x8FCAC257_558EE4E2,     // 21
+
+            // powers of 0.1^16
+            0xE69594BE_C44DE160,     // 1
+            0xCFB11EAD_453994C3,     // 2
+            0xBB127C53_B17EC165,     // 3
+            0xA87FEA27_A539E9B3,     // 4
+            0x97C560BA_6B0919B5,     // 5
+            0x88B402F7_FD7553AB,     // 6
+            0xF64335BC_F065D3A0,     // 7
+            0xDDD0467C_64BCE4C4,     // 8
+            0xC7CABA6E_7C5382ED,     // 9
+            0xB3F4E093_DB73A0B7,     // 10
+            0xA21727DB_38CB0053,     // 11
+            0x91FF8377_5423CC29,     // 12
+            0x8380DEA9_3DA4BC82,     // 13
+            0xECE53CEC_4A314F00,     // 14
+            0xD5605FCD_CF32E217,     // 15
+            0xC0314325_637A1978,     // 16
+            0xAD1C8EAB_5EE43BA2,     // 17
+            0x9BECCE62_836AC5B0,     // 18
+            0x8C71DCD9_BA0B495C,     // 19
+            0xFD00B897_47823938,     // 20
+            0xE3E27A44_4D8D991A,     // 21
+        };
+
+        private static readonly short[] s_Pow10By16ExponentTable = new short[]
+        {
+            // exponents for both powers of 10^16 and 0.1^16
+            54,     // 1
+            107,    // 2
+            160,    // 3
+            213,    // 4
+            266,    // 5
+            319,    // 6
+            373,    // 7
+            426,    // 8
+            479,    // 9
+            532,    // 10
+            585,    // 11
+            638,    // 12
+            691,    // 13
+            745,    // 14
+            798,    // 15
+            851,    // 16
+            904,    // 17
+            957,    // 18
+            1010,   // 19
+            1064,   // 20
+            1117,   // 21
+        };
+
+#if DEBUG
+        private static bool s_CheckedTables = false;
+
+        private static void CheckTables()
+        {
+            ulong val;
+            int exp;
+
+            val = 0xA0000000_00000000;
+            exp = 4; // 10
+
+            CheckPow10MantissaTable(val, exp, new Span<ulong>(s_Pow10MantissaTable, 0, 15), nameof(s_Pow10MantissaTable));
+            CheckPow10ExponentTable(val, exp, new Span<short>(s_Pow10ExponentTable, 0, 15), nameof(s_Pow10ExponentTable));
+
+            val = 0x8E1BC9BF_04000000;
+            exp = 54; //10^16
+
+            CheckPow10MantissaTable(val, exp, new Span<ulong>(s_Pow10By16MantissaTable, 0, 21), nameof(s_Pow10By16MantissaTable));
+            CheckPow10ExponentTable(val, exp, new Span<short>(s_Pow10By16ExponentTable, 0, 21), nameof(s_Pow10By16ExponentTable));
+
+            val = 0xCCCCCCCC_CCCCCCCD;
+            exp = -3; // 0.1
+
+            CheckPow10MantissaTable(val, exp, new Span<ulong>(s_Pow10MantissaTable, 15, 15), nameof(s_Pow10MantissaTable) + " - inv");
+
+            val = 0xE69594BE_C44DE160;
+            exp = -53; // 0.1^16
+
+            CheckPow10MantissaTable(val, exp, new Span<ulong>(s_Pow10By16MantissaTable, 21, 21), nameof(s_Pow10By16MantissaTable) + " - inv");
+        }
+
+        // debug-only verification of the precomputed tables
+        private static void CheckPow10MantissaTable(ulong val, int exp, Span<ulong> table, string name)
+        {
+            ulong multval = val;
+            int mulexp = exp;
+            bool isBad = false;
+
+            for (int i = 0; i < table.Length; i++)
+            {
+                if (table[i] != val)
+                {
+                    if (!isBad)
+                    {
+                        Debug.WriteLine(name);
+                        isBad = true;
+                    }
+                    Debug.WriteLine($"0x{val:X16},     // {i + 1}");
+                }
+
+                exp += mulexp;
+                val = Mul64Precise(val, multval, ref exp);
+            }
+
+            Debug.Assert(!isBad, "NumberToDouble table not correct. Correct version dumped to debug output.");
+        }
+
+        // debug-only verification of the precomputed tables
+        private static void CheckPow10ExponentTable(ulong val, int exp, Span<short> table, string name)
+        {
+            ulong multval = val;
+            int mulexp = exp;
+            bool isBad = false;
+
+            for (int i = 0; i < table.Length; i++)
+            {
+                if (table[i] != exp)
+                {
+                    if (!isBad)
+                    {
+                        Debug.WriteLine(name);
+                        isBad = true;
+                    }
+                    Debug.WriteLine($"{val}, // {i + 1}");
+                }
+
+                exp += mulexp;
+                val = Mul64Precise(val, multval, ref exp);
+            }
+
+            Debug.Assert(!isBad, "NumberToDouble table not correct. Correct version dumped to debug output.");
+        }
+
+        // slower high precision version of Mul64 for computation of the tables
+        private static ulong Mul64Precise(ulong a, ulong b, ref int exp)
+        {
+            ulong hilo = ((Mul32x32To64((uint)(a >> 32), (uint)(b)) >> 1)
+                       + (Mul32x32To64((uint)(a), (uint)(b >> 32)) >> 1)
+                       + (Mul32x32To64((uint)(a), (uint)(b)) >> 33)) >> 30;
+
+            ulong val = Mul32x32To64((uint)(a >> 32), (uint)(b >> 32))
+                      + (hilo >> 1)
+                      + (hilo & 1);
+
+            // normalize
+            if ((val & 0x80000000_00000000) == 0)
+            {
+                val <<= 1;
+                exp--;
+            }
+
+            return val;
+        }
+#endif
+
+        // get 32-bit integer from at most 9 digits
+        private static uint DigitsToInt(char* p, int count)
+        {
+            Debug.Assert((1 <= count) && (count <= 9));
+
+            char* end = (p + count);
+            uint res = (uint)(p[0] - '0');
+
+            for (p++; p < end; p++)
+            {
+                res = (10 * res) + p[0] - '0';
+            }
+
+            return res;
+        }
+
+        private static int GetLength(char* src)
+        {
+            int length = 0;
+
+            while (src[length] != '\0')
+            {
+                length++;
+            }
+
+            return length;
+        }
+
+        // helper function to multiply two 32-bit uints
+        private static ulong Mul32x32To64(uint a, uint b)
+        {
+            return (ulong)(a) * b;
+        }
+
+        // multiply two numbers in the internal integer representation
+        private static ulong Mul64Lossy(ulong a, ulong b, ref int exp)
+        {
+            // 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 & 0x80000000_00000000) == 0)
+            {
+                val <<= 1;
+                exp--;
+            }
+
+            return val;
+        }
+
+        private static double NumberToDouble(ref NumberBuffer number)
+        {
+#if DEBUG
+            
+            if (!s_CheckedTables)
+            {
+                CheckTables();
+                s_CheckedTables = true;
+            }
+#endif
+
+            char* src = number.digits;
+            int total = GetLength(src);
+            int remaining = total;
+
+            // skip the leading zeros
+            while (src[0] == '0')
+            {
+                remaining--;
+                src++;
+            }
+
+            if (remaining == 0)
+            {
+                return number.sign ? -0.0 : 0.0;
+            }
+
+            int count = Math.Min(remaining, 9);
+            remaining -= count;
+            ulong val = DigitsToInt(src, count);
+
+            if (remaining > 0)
+            {
+                count = Math.Min(remaining, 9);
+                remaining -= count;
+
+                // get the denormalized power of 10
+                uint mult = (uint)(s_Pow10MantissaTable[count - 1] >> (64 - s_Pow10ExponentTable[count - 1]));
+                val = Mul32x32To64((uint)(val), mult) + DigitsToInt(src + 9, count);
+            }
+
+            int scale = number.scale - (total - remaining);
+            int absscale = Math.Abs(scale);
+            if (absscale >= 22 * 16)
+            {
+                // overflow / underflow
+                if (scale > 0)
+                {
+                    return number.sign ? double.NegativeInfinity : double.PositiveInfinity;
+                }
+                else
+                {
+                    return number.sign ? -0.0 : 0.0;
+                }
+            }
+
+            int exp = 64;
+
+            // normalize the mantissa
+            if ((val & 0xFFFFFFFF_00000000) == 0) { val <<= 32; exp -= 32; }
+            if ((val & 0xFFFF0000_00000000) == 0) { val <<= 16; exp -= 16; }
+            if ((val & 0xFF000000_00000000) == 0) { val <<= 8; exp -= 8; }
+            if ((val & 0xF0000000_00000000) == 0) { val <<= 4; exp -= 4; }
+            if ((val & 0xC0000000_00000000) == 0) { val <<= 2; exp -= 2; }
+            if ((val & 0x80000000_00000000) == 0) { val <<= 1; exp -= 1; }
+
+            int index = absscale & 15;
+            if (index != 0)
+            {
+                int multexp = s_Pow10ExponentTable[index - 1];
+                // the exponents are shared between the inverted and regular table
+                exp += (scale < 0) ? (-multexp + 1) : multexp;
+
+                ulong multval = s_Pow10MantissaTable[index + ((scale < 0) ? 15 : 0) - 1];
+                val = Mul64Lossy(val, multval, ref exp);
+            }
+
+            index = absscale >> 4;
+            if (index != 0)
+            {
+                int multexp = s_Pow10By16ExponentTable[index - 1];
+                // the exponents are shared between the inverted and regular table
+                exp += (scale < 0) ? (-multexp + 1) : multexp;
+
+                ulong multval = s_Pow10By16MantissaTable[index + ((scale < 0) ? 21 : 0) - 1];
+                val = Mul64Lossy(val, multval, ref exp);
+            }
+
+            // round & scale down
+            if (((uint)(val) & (1 << 10)) != 0)
+            {
+                // IEEE round to even
+                ulong tmp = val + ((1 << 10) - 1) + (((uint)(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.sign)
+            {
+                val |= 0x8000000000000000;
+            }
+
+            return BitConverter.Int64BitsToDouble((long)(val));
+        }
+    }
+}
diff --git a/src/System.Private.CoreLib/src/System/Number.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Number.CoreCLR.cs
deleted file mode 100644 (file)
index 310987a..0000000
+++ /dev/null
@@ -1,14 +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.Runtime.CompilerServices;
-
-namespace System
-{
-    internal static partial class Number
-    {
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        public static extern double NumberToDouble(ref NumberBuffer number);
-    }
-}
index a5a0e63..2f990ad 100644 (file)
@@ -7,7 +7,6 @@ endif(PerfCountersSupportedBuild)
 set(BCLTYPE_SOURCES
     arraynative.cpp
     arrayhelpers.cpp
-    number.cpp
     oavariant.cpp
     objectnative.cpp
     stringnative.cpp
diff --git a/src/classlibnative/bcltype/number.cpp b/src/classlibnative/bcltype/number.cpp
deleted file mode 100644 (file)
index 8fe62eb..0000000
+++ /dev/null
@@ -1,441 +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.
-//
-// File: Number.cpp
-//
-
-//
-
-#include "common.h"
-#include "number.h"
-
-typedef wchar_t wchar;
-
-/*===========================================================
-    Portable NumberToDouble implementation
-    --------------------------------------
-
-    - does the conversion with the best possible precision.
-    - does not use any float arithmetic so it is not sensitive
-    to differences in precision of floating point calculations
-    across platforms.
-
-    The internal integer representation of the float number is
-    UINT64 mantissa + INT exponent. The mantissa is kept normalized
-    ie with the most significant one being 63-th bit of UINT64.
-===========================================================*/
-
-//
-// get 32-bit integer from at most 9 digits
-//
-static unsigned DigitsToInt(__in_ecount(count) wchar* p, int count)
-{
-    LIMITED_METHOD_CONTRACT
-
-    _ASSERTE(1 <= count && count <= 9);
-    wchar* end = p + count;
-    unsigned res = *p - '0';
-    for ( p = p + 1; p < end; p++) {
-        res = 10 * res + *p - '0';
-    }
-    return res;
-}
-
-//
-// helper macro to multiply two 32-bit uints
-//
-#define Mul32x32To64(a, b) ((UINT64)((UINT32)(a)) * (UINT64)((UINT32)(b)))
-
-
-//
-// multiply two numbers in the internal integer representation
-//
-static UINT64 Mul64Lossy(UINT64 a, UINT64 b, INT* pexp)
-{
-    LIMITED_METHOD_CONTRACT
-
-    // it's ok to losse 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
-    UINT64 val = Mul32x32To64(a >> 32, b >> 32) +
-        (Mul32x32To64(a >> 32, b) >> 32) +
-        (Mul32x32To64(a, b >> 32) >> 32);
-
-    // normalize
-    if ((val & I64(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.
-//
-
-static const UINT64 rgval64Power10[] = {
-// powers of 10
-/*1*/ I64(0xa000000000000000),
-/*2*/ I64(0xc800000000000000),
-/*3*/ I64(0xfa00000000000000),
-/*4*/ I64(0x9c40000000000000),
-/*5*/ I64(0xc350000000000000),
-/*6*/ I64(0xf424000000000000),
-/*7*/ I64(0x9896800000000000),
-/*8*/ I64(0xbebc200000000000),
-/*9*/ I64(0xee6b280000000000),
-/*10*/ I64(0x9502f90000000000),
-/*11*/ I64(0xba43b74000000000),
-/*12*/ I64(0xe8d4a51000000000),
-/*13*/ I64(0x9184e72a00000000),
-/*14*/ I64(0xb5e620f480000000),
-/*15*/ I64(0xe35fa931a0000000),
-
-// powers of 0.1
-/*1*/ I64(0xcccccccccccccccd),
-/*2*/ I64(0xa3d70a3d70a3d70b),
-/*3*/ I64(0x83126e978d4fdf3c),
-/*4*/ I64(0xd1b71758e219652e),
-/*5*/ I64(0xa7c5ac471b478425),
-/*6*/ I64(0x8637bd05af6c69b7),
-/*7*/ I64(0xd6bf94d5e57a42be),
-/*8*/ I64(0xabcc77118461ceff),
-/*9*/ I64(0x89705f4136b4a599),
-/*10*/ I64(0xdbe6fecebdedd5c2),
-/*11*/ I64(0xafebff0bcb24ab02),
-/*12*/ I64(0x8cbccc096f5088cf),
-/*13*/ I64(0xe12e13424bb40e18),
-/*14*/ I64(0xb424dc35095cd813),
-/*15*/ I64(0x901d7cf73ab0acdc),
-};
-
-static const INT8 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,
-};
-
-static const UINT64 rgval64Power10By16[] = {
-// powers of 10^16
-/*1*/ I64(0x8e1bc9bf04000000),
-/*2*/ I64(0x9dc5ada82b70b59e),
-/*3*/ I64(0xaf298d050e4395d6),
-/*4*/ I64(0xc2781f49ffcfa6d4),
-/*5*/ I64(0xd7e77a8f87daf7fa),
-/*6*/ I64(0xefb3ab16c59b14a0),
-/*7*/ I64(0x850fadc09923329c),
-/*8*/ I64(0x93ba47c980e98cde),
-/*9*/ I64(0xa402b9c5a8d3a6e6),
-/*10*/ I64(0xb616a12b7fe617a8),
-/*11*/ I64(0xca28a291859bbf90),
-/*12*/ I64(0xe070f78d39275566),
-/*13*/ I64(0xf92e0c3537826140),
-/*14*/ I64(0x8a5296ffe33cc92c),
-/*15*/ I64(0x9991a6f3d6bf1762),
-/*16*/ I64(0xaa7eebfb9df9de8a),
-/*17*/ I64(0xbd49d14aa79dbc7e),
-/*18*/ I64(0xd226fc195c6a2f88),
-/*19*/ I64(0xe950df20247c83f8),
-/*20*/ I64(0x81842f29f2cce373),
-/*21*/ I64(0x8fcac257558ee4e2),
-
-// powers of 0.1^16
-/*1*/ I64(0xe69594bec44de160),
-/*2*/ I64(0xcfb11ead453994c3),
-/*3*/ I64(0xbb127c53b17ec165),
-/*4*/ I64(0xa87fea27a539e9b3),
-/*5*/ I64(0x97c560ba6b0919b5),
-/*6*/ I64(0x88b402f7fd7553ab),
-/*7*/ I64(0xf64335bcf065d3a0),
-/*8*/ I64(0xddd0467c64bce4c4),
-/*9*/ I64(0xc7caba6e7c5382ed),
-/*10*/ I64(0xb3f4e093db73a0b7),
-/*11*/ I64(0xa21727db38cb0053),
-/*12*/ I64(0x91ff83775423cc29),
-/*13*/ I64(0x8380dea93da4bc82),
-/*14*/ I64(0xece53cec4a314f00),
-/*15*/ I64(0xd5605fcdcf32e217),
-/*16*/ I64(0xc0314325637a1978),
-/*17*/ I64(0xad1c8eab5ee43ba2),
-/*18*/ I64(0x9becce62836ac5b0),
-/*19*/ I64(0x8c71dcd9ba0b495c),
-/*20*/ I64(0xfd00b89747823938),
-/*21*/ I64(0xe3e27a444d8d991a),
-};
-
-static const INT16 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,
-};
-
-#ifdef _DEBUG
-//
-// slower high precision version of Mul64 for computation of the tables
-//
-static UINT64 Mul64Precise(UINT64 a, UINT64 b, INT* pexp)
-{
-    LIMITED_METHOD_CONTRACT
-
-    UINT64 hilo =
-        ((Mul32x32To64(a >> 32, b) >> 1) +
-        (Mul32x32To64(a, b >> 32) >> 1) +
-        (Mul32x32To64(a, b) >> 33)) >> 30;
-
-    UINT64 val = Mul32x32To64(a >> 32, b >> 32) + (hilo >> 1) + (hilo & 1);
-
-    // normalize
-    if ((val & I64(0x8000000000000000)) == 0) { val <<= 1; *pexp -= 1; }
-
-    return val;
-}
-
-
-//
-// debug-only verification of the precomputed tables
-//
-static void CheckTable(UINT64 val, INT exp, LPCVOID table, int size, LPCSTR name, int tabletype)
-{
-    WRAPPER_NO_CONTRACT
-
-    UINT64 multval = val;
-    INT mulexp = exp;
-    bool fBad = false;
-    for (int i = 0; i < size; i++) {
-        switch (tabletype) {
-        case 1:
-            if (((UINT64*)table)[i] != val) {
-                if (!fBad) {
-                    fprintf(stderr, "%s:\n", name);
-                    fBad = true;
-                }
-                fprintf(stderr, "/*%d*/ I64(0x%I64x),\n", i+1, val);
-            }
-            break;
-        case 2:
-            if (((INT8*)table)[i] != exp) {
-                if (!fBad) {
-                    fprintf(stderr, "%s:\n", name);
-                    fBad = true;
-                }
-                fprintf(stderr, "/*%d*/ %d,\n", i+1, exp);
-            }
-            break;
-        case 3:
-            if (((INT16*)table)[i] != exp) {
-                if (!fBad) {
-                    fprintf(stderr, "%s:\n", name);
-                    fBad = true;
-                }
-                fprintf(stderr, "/*%d*/ %d,\n", i+1, exp);
-            }
-            break;
-        default:
-            _ASSERTE(false);
-            break;
-        }
-
-        exp += mulexp;
-        val = Mul64Precise(val, multval, &exp);
-    }
-    _ASSERTE(!fBad || !"NumberToDouble table not correct. Correct version dumped to stderr.");
-}
-
-void CheckTables()
-{
-    WRAPPER_NO_CONTRACT
-
-    UINT64 val; INT exp;
-
-    val = I64(0xa000000000000000); exp = 4; // 10
-    CheckTable(val, exp, rgval64Power10, 15, "rgval64Power10", 1);
-    CheckTable(val, exp, rgexp64Power10, 15, "rgexp64Power10", 2);
-
-    val = I64(0x8e1bc9bf04000000); exp = 54; //10^16
-    CheckTable(val, exp, rgval64Power10By16, 21, "rgval64Power10By16", 1);
-    CheckTable(val, exp, rgexp64Power10By16, 21, "rgexp64Power10By16", 3);
-
-    val = I64(0xCCCCCCCCCCCCCCCD); exp = -3; // 0.1
-    CheckTable(val, exp, rgval64Power10+15, 15, "rgval64Power10 - inv", 1);
-
-    val = I64(0xe69594bec44de160); exp = -53; // 0.1^16
-    CheckTable(val, exp, rgval64Power10By16+21, 21, "rgval64Power10By16 - inv", 1);
-}
-#endif // _DEBUG
-
-void NumberToDouble(NUMBER* number, double* value)
-{
-    WRAPPER_NO_CONTRACT
-
-    UINT64 val;
-    INT exp;
-    wchar* src = number->digits;
-    int remaining;
-    int total;
-    int count;
-    int scale;
-    int absscale;
-    int index;
-
-#ifdef _DEBUG
-    static bool fCheckedTables = false;
-    if (!fCheckedTables) {
-        CheckTables();
-        fCheckedTables = true;
-    }
-#endif // _DEBUG
-
-    total = (int)wcslen(src);
-    remaining = total;
-
-    // skip the leading zeros
-    while (*src == '0') {
-        remaining--;
-        src++;
-    }
-
-    if (remaining == 0) {
-        *value = 0;
-        goto done;
-    }
-
-    count = min(remaining, 9);
-    remaining -= count;
-    val = DigitsToInt(src, count);
-
-    if (remaining > 0) {
-        count = min(remaining, 9);
-        remaining -= count;
-
-        // get the denormalized power of 10
-        UINT32 mult = (UINT32)(rgval64Power10[count-1] >> (64 - rgexp64Power10[count-1]));
-        val = Mul32x32To64(val, mult) + DigitsToInt(src+9, count);
-    }
-
-    scale = number->scale - (total - remaining);
-    absscale = abs(scale);
-    if (absscale >= 22 * 16) {
-        // overflow / underflow
-        *(UINT64*)value = (scale > 0) ? I64(0x7FF0000000000000) : 0;
-        goto done;
-    }
-
-    exp = 64;
-
-    // normalize the mantissa
-    if ((val & I64(0xFFFFFFFF00000000)) == 0) { val <<= 32; exp -= 32; }
-    if ((val & I64(0xFFFF000000000000)) == 0) { val <<= 16; exp -= 16; }
-    if ((val & I64(0xFF00000000000000)) == 0) { val <<= 8; exp -= 8; }
-    if ((val & I64(0xF000000000000000)) == 0) { val <<= 4; exp -= 4; }
-    if ((val & I64(0xC000000000000000)) == 0) { val <<= 2; exp -= 2; }
-    if ((val & I64(0x8000000000000000)) == 0) { val <<= 1; exp -= 1; }
-
-    index = absscale & 15;
-    if (index) {
-        INT multexp = rgexp64Power10[index-1];
-        // the exponents are shared between the inverted and regular table
-        exp += (scale < 0) ? (-multexp + 1) : multexp;
-
-        UINT64 multval = rgval64Power10[index + ((scale < 0) ? 15 : 0) - 1];
-        val = Mul64Lossy(val, multval, &exp);
-    }
-
-    index = absscale >> 4;
-    if (index) {
-        INT multexp = rgexp64Power10By16[index-1];
-        // the exponents are shared between the inverted and regular table
-        exp += (scale < 0) ? (-multexp + 1) : multexp;
-
-        UINT64 multval = rgval64Power10By16[index + ((scale < 0) ? 21 : 0) - 1];
-        val = Mul64Lossy(val, multval, &exp);
-    }
-
-
-    // round & scale down
-    if ((UINT32)val & (1 << 10))
-    {
-        // IEEE round to even
-        UINT64 tmp = val + ((1 << 10) - 1) + (((UINT32)val >> 11) & 1);
-        if (tmp < val) {
-            // overflow
-            tmp = (tmp >> 1) | I64(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  >= I64(0x8000000000000058))) {
-            // round X where {Epsilon > X >= 2.470328229206232730000000E-324} up to Epsilon (instead of down to zero)
-            val = I64(0x0000000000000001);
-        }
-        else if (exp <= -52) {
-            // underflow
-            val = 0;
-        }
-        else {
-            // denormalized
-            val >>= (-exp + 11 + 1);
-        }
-    }
-    else if (exp >= 0x7FF) {
-        // overflow
-        val = I64(0x7FF0000000000000);
-    }
-    else {
-        // normal postive exponent case
-        val = ((UINT64)exp << 52) + ((val >> 11) & I64(0x000FFFFFFFFFFFFF));
-    }
-
-    *(UINT64*)value = val;
-
-done:
-    if (number->sign) *(UINT64*)value |= I64(0x8000000000000000);
-}
-
-FCIMPL1(double, COMNumber::NumberToDoubleFC, NUMBER* number)
-{
-    FCALL_CONTRACT;
-
-    double d = 0;
-    NumberToDouble(number, &d);
-    return d;
-}
-FCIMPLEND
diff --git a/src/classlibnative/bcltype/number.h b/src/classlibnative/bcltype/number.h
deleted file mode 100644 (file)
index 2359deb..0000000
+++ /dev/null
@@ -1,47 +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.
-//
-// File: Number.h
-//
-
-//
-
-#ifndef _NUMBER_H_
-#define _NUMBER_H_
-
-#include <pshpack1.h>
-
-#define NUMBER_MAXDIGITS 50
-
-static const double LOG10V2 = 0.30102999566398119521373889472449;
-
-// DRIFT_FACTOR = 1 - LOG10V2 - epsilon (a small number account for drift of floating point multiplication)
-static const double DRIFT_FACTOR = 0.69;
-
-enum NUMBER_KIND : int {
-    NUMBER_KIND_Unknown = 0,
-    NUMBER_KIND_Integer = 1,
-    NUMBER_KIND_Decimal = 2,
-    NUMBER_KIND_Double = 3
-};
-
-struct NUMBER {
-    int precision;                          //  0
-    int scale;                              //  4
-    int sign;                               //  8
-    NUMBER_KIND kind;                       // 12
-    wchar_t* allDigits;                     // 16
-    wchar_t digits[NUMBER_MAXDIGITS + 1];   // 20 or 24
-    NUMBER() : precision(0), scale(0), sign(0), kind(NUMBER_KIND_Unknown), allDigits(NULL) {}
-};
-
-class COMNumber
-{
-public:
-    static FCDECL1(double, NumberToDoubleFC, NUMBER* number);
-};
-
-#include <poppack.h>
-
-#endif // _NUMBER_H_
index 7983f7f..cd9638a 100644 (file)
@@ -739,10 +739,6 @@ FCFuncStart(gWaitHandleFuncs)
     FCFuncElement("SignalAndWaitOne", WaitHandleNative::CorSignalAndWaitOneNative)
 FCFuncEnd()
 
-FCFuncStart(gNumberFuncs)
-    FCFuncElement("NumberToDouble", COMNumber::NumberToDoubleFC)
-FCFuncEnd()
-
 #ifdef FEATURE_COMINTEROP
 FCFuncStart(gVariantFuncs)
     FCFuncElement("SetFieldsObject", COMVariant::SetFieldsObject)
@@ -1304,7 +1300,6 @@ FCClassElement("MngdSafeArrayMarshaler", "System.StubHelpers", gMngdSafeArrayMar
 FCClassElement("ModuleBuilder", "System.Reflection.Emit", gCOMModuleBuilderFuncs)
 FCClassElement("ModuleHandle", "System", gCOMModuleHandleFuncs)
 FCClassElement("Monitor", "System.Threading", gMonitorFuncs)
-FCClassElement("Number", "System", gNumberFuncs)
 #ifdef FEATURE_COMINTEROP
 FCClassElement("OAVariantLib", "Microsoft.Win32", gOAVariantFuncs)
 #endif
index a526ebd..240c127 100644 (file)
@@ -42,7 +42,6 @@
 #include "floatdouble.h"
 #include "floatsingle.h"
 #include "comdatetime.h"
-#include "number.h"
 #include "compatibilityswitch.h"
 #include "debugdebugger.h"
 #include "assemblyname.hpp"