Move Decimal to shared (dotnet/coreclr#18948)
authorPent Ploompuu <kaalikas@gmail.com>
Tue, 17 Jul 2018 15:41:39 +0000 (18:41 +0300)
committerJan Kotas <jkotas@microsoft.com>
Tue, 17 Jul 2018 15:41:39 +0000 (08:41 -0700)
* Move Decimal to shared

* Remove DecimalCanonicalize{Internal}

Commit migrated from https://github.com/dotnet/coreclr/commit/2b50bba8131acca2ab535e144796941ad93487b7

28 files changed:
src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/coreclr/src/System.Private.CoreLib/src/System/Currency.cs
src/coreclr/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs [deleted file]
src/coreclr/src/System.Private.CoreLib/src/System/Number.CoreCLR.cs
src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs
src/coreclr/src/classlibnative/bcltype/CMakeLists.txt
src/coreclr/src/classlibnative/bcltype/currency.cpp [deleted file]
src/coreclr/src/classlibnative/bcltype/currency.h [deleted file]
src/coreclr/src/classlibnative/bcltype/decimal.cpp [deleted file]
src/coreclr/src/classlibnative/bcltype/decimal.h [deleted file]
src/coreclr/src/classlibnative/bcltype/number.cpp
src/coreclr/src/classlibnative/bcltype/number.h
src/coreclr/src/inc/utilcode.h
src/coreclr/src/palrt/CMakeLists.txt
src/coreclr/src/palrt/decarith.cpp [deleted file]
src/coreclr/src/palrt/decconv.cpp [deleted file]
src/coreclr/src/vm/ecalllist.h
src/coreclr/src/vm/fieldmarshaler.cpp
src/coreclr/src/vm/ilmarshalers.cpp
src/coreclr/src/vm/mscorlib.cpp
src/coreclr/src/vm/mscorlib.h
src/coreclr/src/vm/olevariant.cpp
src/coreclr/src/vm/stubhelpers.cpp
src/coreclr/src/vm/stubhelpers.h
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Decimal.cs [moved from src/coreclr/src/System.Private.CoreLib/src/System/Decimal.cs with 69% similarity]
src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs

index c807f94..9a2fc68 100644 (file)
     <Compile Include="$(BclSourcesRoot)\System\BadImageFormatException.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Buffer.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Currency.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Decimal.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Decimal.DecCalc.cs" />
     <Compile Include="$(BclSourcesRoot)\System\DefaultBinder.CanConvert.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Enum.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Environment.cs" />
index 81d0bbf..c9e8dc0 100644 (file)
@@ -2,12 +2,6 @@
 // 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;
-using System.Globalization;
-using System.Runtime.CompilerServices;
-using System.Runtime.Versioning;
-
 namespace System
 {
     internal struct Currency
@@ -18,46 +12,17 @@ namespace System
         //
         public Currency(decimal value)
         {
-            m_value = decimal.ToCurrency(value).m_value;
-        }
-
-        // Constructs a Currency from a long value without scaling. The
-        // ignored parameter exists only to distinguish this constructor
-        // from the constructor that takes a long.  Used only in the System 
-        // package, especially in Variant.
-        internal Currency(long value, int ignored)
-        {
-            m_value = value;
-        }
-
-        // Creates a Currency from an OLE Automation Currency.  This method
-        // applies no scaling to the Currency value, essentially doing a bitwise
-        // copy.
-        // 
-        public static Currency FromOACurrency(long cy)
-        {
-            return new Currency(cy, 0);
-        }
-
-        //Creates an OLE Automation Currency from a Currency instance.  This 
-        // method applies no scaling to the Currency value, essentially doing 
-        // a bitwise copy.
-        // 
-        public long ToOACurrency()
-        {
-            return m_value;
+            m_value = decimal.ToOACurrency(value);
         }
+    }
 
-        // Converts a Currency to a decimal.
+    partial struct Decimal
+    {
+        // Constructs a Decimal from a Currency value.
         //
-        public static decimal ToDecimal(Currency c)
+        internal Decimal(Currency value)
         {
-            decimal result = new decimal();
-            FCallToDecimal(ref result, c);
-            return result;
+            this = FromOACurrency(value.m_value);
         }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallToDecimal(ref decimal result, Currency c);
     }
 }
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs
deleted file mode 100644 (file)
index d18a52e..0000000
+++ /dev/null
@@ -1,96 +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;
-using Internal.Runtime.CompilerServices;
-
-namespace System
-{
-    public partial struct Decimal
-    {
-        internal static uint DecDivMod1E9(ref decimal value)
-        {
-            return D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0,
-                                                          ref Unsafe.As<int, uint>(ref value.hi)),
-                                             ref Unsafe.As<int, uint>(ref value.mid)),
-                                ref Unsafe.As<int, uint>(ref value.lo));
-
-            uint D32DivMod1E9(uint hi32, ref uint lo32)
-            {
-                ulong n = (ulong)hi32 << 32 | lo32;
-                lo32 = (uint)(n / 1000000000);
-                return (uint)(n % 1000000000);
-            }
-        }
-
-        private static int GetHashCode(ref decimal d)
-        {
-            if ((d.Low | d.Mid | d.High) == 0)
-                return 0;
-
-            uint flags = (uint)d.flags;
-            if ((flags & ScaleMask) == 0 || (d.Low & 1) != 0)
-                return (int)(flags ^ d.High ^ d.Mid ^ d.Low);
-
-            int scale = (byte)(flags >> ScaleShift);
-            uint low = d.Low;
-            ulong high64 = ((ulong)d.High << 32) | d.Mid;
-
-            Unscale(ref low, ref high64, ref scale);
-
-            flags = ((flags) & ~(uint)ScaleMask) | (uint)scale << ScaleShift;
-            return (int)(flags ^ (uint)(high64 >> 32) ^ (uint)high64 ^ low);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static bool Div96ByConst(ref ulong high64, ref uint low, uint pow)
-        {
-            ulong div64;
-#if !BIT64
-            if (high64 <= uint.MaxValue)
-            {
-                div64 = ((high64 << 32) | low) / pow;
-                if (low == (uint)div64 * pow)
-                {
-                    low = (uint)div64;
-                    high64 = div64 >> 32;
-                    return true;
-                }
-                return false;
-            }
-#endif
-            div64 = high64 / pow;
-            uint div = (uint)((((high64 - (uint)div64 * pow) << 32) | low) / pow);
-            if (low == div * pow)
-            {
-                high64 = div64;
-                low = div;
-                return true;
-            }
-            return false;
-        }
-
-        // Normalize (unscale) the number by trying to divide out 10^8, 10^4, 10^2, and 10^1.
-        // If a division by one of these powers returns a zero remainder, then we keep the quotient.
-        // 
-        // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10 we can extract. 
-        // We use this as a quick test on whether to try a given power.
-        // 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static void Unscale(ref uint low, ref ulong high64, ref int scale)
-        {
-            while ((byte)low == 0 && scale >= 8 && Div96ByConst(ref high64, ref low, 100000000))
-                scale -= 8;
-
-            if ((low & 0xF) == 0 && scale >= 4 && Div96ByConst(ref high64, ref low, 10000))
-                scale -= 4;
-
-            if ((low & 3) == 0 && scale >= 2 && Div96ByConst(ref high64, ref low, 100))
-                scale -= 2;
-
-            if ((low & 1) == 0 && scale >= 1 && Div96ByConst(ref high64, ref low, 10))
-                scale--;
-        }
-    }
-}
index e14db02..30e70d0 100644 (file)
@@ -13,8 +13,5 @@ namespace System
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double NumberToDouble(ref NumberBuffer number);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        public static extern bool NumberBufferToDecimal(ref NumberBuffer number, ref decimal value);
     }
 }
index 069f752..6d9e7a8 100644 (file)
@@ -1695,9 +1695,6 @@ namespace System.StubHelpers
         internal static extern unsafe int strlen(sbyte* ptr);
 
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern void DecimalCanonicalizeInternal(ref decimal dec);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
         internal static extern unsafe void FmtClassUpdateNativeInternal(object obj, byte* pNative, ref CleanupWorkList pCleanupWorkList);
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         internal static extern unsafe void FmtClassUpdateCLRInternal(object obj, byte* pNative);
index 62cf968..41cf3cf 100644 (file)
@@ -8,8 +8,6 @@ set(BCLTYPE_SOURCES
     arraynative.cpp
     arrayhelpers.cpp
     bignum.cpp
-    currency.cpp
-    decimal.cpp
     diyfp.cpp
     grisu3.cpp
     number.cpp
diff --git a/src/coreclr/src/classlibnative/bcltype/currency.cpp b/src/coreclr/src/classlibnative/bcltype/currency.cpp
deleted file mode 100644 (file)
index 4506105..0000000
+++ /dev/null
@@ -1,42 +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: Currency.cpp
-//
-
-//
-
-#include "common.h"
-#include "object.h"
-#include "excep.h"
-#include "frames.h"
-#include "vars.hpp"
-#include "currency.h"
-#include "string.h"
-
-
-FCIMPL2_IV(void, COMCurrency::DoToDecimal, DECIMAL * result, CY c)
-{
-    FCALL_CONTRACT;
-
-    // GC could only happen when exception is thrown, no need to protect result
-    HELPER_METHOD_FRAME_BEGIN_0();
-
-    _ASSERTE(result);
-    HRESULT hr = VarDecFromCy(c, result);
-    if (FAILED(hr))
-    {
-        // Didn't expect to get here.  Update code for this HR.
-        _ASSERTE(S_OK == hr);
-        COMPlusThrowHR(hr);
-    }
-
-    if (FAILED(DecimalCanonicalize(result)))
-        COMPlusThrow(kOverflowException, W("Overflow_Currency"));
-    
-    result->wReserved = 0;
-
-    HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
diff --git a/src/coreclr/src/classlibnative/bcltype/currency.h b/src/coreclr/src/classlibnative/bcltype/currency.h
deleted file mode 100644 (file)
index a1ba64e..0000000
+++ /dev/null
@@ -1,24 +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: Currency.h
-//
-
-//
-
-#ifndef _CURRENCY_H_
-#define _CURRENCY_H_
-
-#include <oleauto.h>
-#include <pshpack1.h>
-
-class COMCurrency 
-{
-public:
-    static FCDECL2_IV(void, DoToDecimal,  DECIMAL * result, CY c);
-};
-
-#include <poppack.h>
-
-#endif // _CURRENCY_H_
diff --git a/src/coreclr/src/classlibnative/bcltype/decimal.cpp b/src/coreclr/src/classlibnative/bcltype/decimal.cpp
deleted file mode 100644 (file)
index 729b19f..0000000
+++ /dev/null
@@ -1,2534 +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: decimal.cpp
-//
-
-//
-
-#include "common.h"
-#include "object.h"
-#include "excep.h"
-#include "frames.h"
-#include "vars.hpp"
-#include "decimal.h"
-#include "string.h"
-
-LONG g_OLEAUT32_Loaded = 0;
-
-unsigned int DecDivMod1E9(DECIMAL* value);
-void DecMul10(DECIMAL* value);
-void DecAddInt32(DECIMAL* value, unsigned int i);
-
-#define COPYDEC(dest, src) {DECIMAL_SIGNSCALE(dest) = DECIMAL_SIGNSCALE(src); DECIMAL_HI32(dest) = DECIMAL_HI32(src); DECIMAL_LO64_SET(dest, DECIMAL_LO64_GET(src));}
-
-FCIMPL2_IV(void, COMDecimal::InitSingle, DECIMAL *_this, float value)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    _ASSERTE(_this != NULL);
-    HRESULT hr = VarDecFromR4(value, _this);
-    if (FAILED(hr))
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-    _this->wReserved = 0;
-}
-FCIMPLEND
-
-FCIMPL2_IV(void, COMDecimal::InitDouble, DECIMAL *_this, double value)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    _ASSERTE(_this != NULL);
-    HRESULT hr = VarDecFromR8(value, _this);
-    if (FAILED(hr))
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-    _this->wReserved = 0;
-}
-FCIMPLEND
-
-
-#ifdef _MSC_VER
-// C4702: unreachable code on IA64 retail
-#pragma warning(push)
-#pragma warning(disable:4702)
-#endif
-FCIMPL2(INT32, COMDecimal::DoCompare, DECIMAL * d1, DECIMAL * d2)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    HRESULT hr = VarDecCmp(d1, d2);
-    if (FAILED(hr) || (int)hr == VARCMP_NULL) {
-        _ASSERTE(!"VarDecCmp failed in Decimal::Compare");
-        FCThrowRes(kOverflowException, W("Overflow_Decimal"));
-    }
-    
-    INT32 retVal = ((int)hr) - 1;
-    FC_GC_POLL_RET ();
-    return retVal;
-}
-FCIMPLEND
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-FCIMPL1(void, COMDecimal::DoFloor, DECIMAL * d)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    DECIMAL decRes;
-    HRESULT hr;
-    hr = VarDecInt(d, &decRes);
-
-    // VarDecInt can't overflow, as of source for OleAut32 build 4265.
-    // It only returns NOERROR
-    _ASSERTE(hr==NOERROR);
-
-    // copy decRes into d
-    COPYDEC(*d, decRes)
-    d->wReserved = 0;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
-FCIMPL3(void, COMDecimal::DoMultiply, DECIMAL * d1, DECIMAL * d2, CLR_BOOL * overflowed)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    DECIMAL decRes;
-
-    // GC is only triggered for throwing, no need to protect result 
-    HRESULT hr = VarDecMul(d1, d2, &decRes);
-    if (FAILED(hr)) {
-        *overflowed = true;
-        FC_GC_POLL();
-        return;
-    }
-
-    // copy decRes into d1
-    COPYDEC(*d1, decRes)
-    d1->wReserved = 0;
-    *overflowed = false;
-    FC_GC_POLL();
-} 
-FCIMPLEND
-
-
-FCIMPL2(void, COMDecimal::DoMultiplyThrow, DECIMAL * d1, DECIMAL * d2)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    DECIMAL decRes;
-
-    // GC is only triggered for throwing, no need to protect result 
-    HRESULT hr = VarDecMul(d1, d2, &decRes);
-    if (FAILED(hr)) {
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-    }
-
-    // copy decRes into d1
-    COPYDEC(*d1, decRes)
-    d1->wReserved = 0;
-    FC_GC_POLL();
-} 
-FCIMPLEND
-
-FCIMPL2(void, COMDecimal::DoRound, DECIMAL * d, INT32 decimals)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    DECIMAL decRes;
-    
-    // GC is only triggered for throwing, no need to protect result 
-    if (decimals < 0 || decimals > 28)
-        FCThrowArgumentOutOfRangeVoid(W("decimals"), W("ArgumentOutOfRange_DecimalRound"));
-    HRESULT hr = VarDecRound(d, decimals, &decRes);
-    if (FAILED(hr))
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-
-    // copy decRes into d
-    COPYDEC(*d, decRes)
-    d->wReserved = 0;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
-FCIMPL2_IV(void, COMDecimal::DoToCurrency, CY * result, DECIMAL d)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    // GC is only triggered for throwing, no need to protect result
-    HRESULT hr = VarCyFromDec(&d, result);
-    if (FAILED(hr)) {
-        _ASSERTE(hr != E_INVALIDARG);
-        FCThrowResVoid(kOverflowException, W("Overflow_Currency"));
-    }
-}
-FCIMPLEND
-
-FCIMPL1(double, COMDecimal::ToDouble, FC_DECIMAL d)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    double result = 0.0;
-    // Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
-    VarR8FromDec(&d, &result);
-    return result;
-}
-FCIMPLEND
-
-FCIMPL1(INT32, COMDecimal::ToInt32, FC_DECIMAL d)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    DECIMAL result;
-    HRESULT hr = VarDecRound(&d, 0, &result);
-    if (FAILED(hr))
-        FCThrowRes(kOverflowException, W("Overflow_Decimal"));
-
-    result.wReserved = 0;
-    
-    if( DECIMAL_SCALE(result) != 0) {
-        d = result;
-        VarDecFix(&d, &result);
-    }
-
-    if (DECIMAL_HI32(result) == 0 && DECIMAL_MID32(result) == 0) {
-        INT32 i = DECIMAL_LO32(result);
-        if ((INT16)DECIMAL_SIGNSCALE(result) >= 0) {
-            if (i >= 0) return i;
-        }
-        else {
-            // Int32.MinValue is represented as sign being negative
-            // and Lo32 being 0x80000000 (-ve number). Return that as is without
-            // reversing the sign of the number.
-            if(i == 0x80000000) return i;
-            i = -i;
-            if (i <= 0) return i;
-        }
-    }
-    FCThrowRes(kOverflowException, W("Overflow_Int32"));    
-}
-FCIMPLEND
-
-FCIMPL1(float, COMDecimal::ToSingle, FC_DECIMAL d)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    float result = 0.0f;
-    // Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
-    VarR4FromDec(&d, &result);
-    return result;
-}
-FCIMPLEND
-
-FCIMPL1(void, COMDecimal::DoTruncate, DECIMAL * d)
-{
-    FCALL_CONTRACT;
-
-    ENSURE_OLEAUT32_LOADED();
-
-    DECIMAL decRes;
-
-    VarDecFix(d, &decRes);
-
-    // copy decRes into d
-    COPYDEC(*d, decRes)
-    d->wReserved = 0;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
-int COMDecimal::NumberToDecimal(NUMBER* number, DECIMAL* value)
-{
-    WRAPPER_NO_CONTRACT
-    _ASSERTE(number != NULL);
-    _ASSERTE(value != NULL);
-
-    DECIMAL d;
-    d.wReserved = 0;
-    DECIMAL_SIGNSCALE(d) = 0;
-    DECIMAL_HI32(d) = 0;
-    DECIMAL_LO32(d) = 0;
-    DECIMAL_MID32(d) = 0;
-    wchar_t* p = number->digits;
-    _ASSERT(p != NULL);
-    int e = number->scale;
-    if (!*p) {
-        // 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
-        if (e > 0) {
-            e = 0;
-        }
-    } else {
-        if (e > DECIMAL_PRECISION) return 0;
-        while ((e > 0 || (*p && e > -28)) &&
-                (DECIMAL_HI32(d) < 0x19999999 || (DECIMAL_HI32(d) == 0x19999999 &&
-                    (DECIMAL_MID32(d) < 0x99999999 || (DECIMAL_MID32(d) == 0x99999999 &&
-                        (DECIMAL_LO32(d) < 0x99999999 || (DECIMAL_LO32(d) == 0x99999999 && *p <= '5'))))))) {
-            DecMul10(&d);
-            if (*p) DecAddInt32(&d, *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 roundinp 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) {
-                DecAddInt32(&d, 1);
-                if ((DECIMAL_HI32(d) | DECIMAL_MID32(d) | DECIMAL_LO32(d)) == 0) {
-                    DECIMAL_HI32(d) = 0x19999999;
-                    DECIMAL_MID32(d) = 0x99999999;
-                    DECIMAL_LO32(d) = 0x9999999A;
-                    e++;
-                }
-            }
-        }
-    }
-    if (e > 0) return 0;
-    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.
-        DECIMAL_SIGNSCALE(d) = 0;
-        DECIMAL_HI32(d) = 0;
-        DECIMAL_LO32(d) = 0;
-        DECIMAL_MID32(d) = 0;
-        DECIMAL_SCALE(d) = (DECIMAL_PRECISION - 1);
-    }
-    else 
-    {
-        DECIMAL_SCALE(d) = static_cast<BYTE>(-e);
-    }
-    DECIMAL_SIGN(d) = number->sign? DECIMAL_NEG: 0;
-    *value = d;
-    return 1;
-}
-
-#if defined(_TARGET_X86_)
-        
-#pragma warning(disable:4035)
-
-unsigned int DecDivMod1E9(DECIMAL* value)
-{
-    LIMITED_METHOD_CONTRACT
-
-    _asm {
-        mov     ebx,value
-        mov     ecx,1000000000
-        xor     edx,edx
-        mov     eax,[ebx+4]
-        div     ecx
-        mov     [ebx+4],eax
-        mov     eax,[ebx+12]
-        div     ecx
-        mov     [ebx+12],eax
-        mov     eax,[ebx+8]
-        div     ecx
-        mov     [ebx+8],eax
-        mov     eax,edx
-    }
-}
-
-void DecMul10(DECIMAL* value)
-{
-    LIMITED_METHOD_CONTRACT
-
-    _asm {
-        mov     ebx,value
-        mov     eax,[ebx+8]
-        mov     edx,[ebx+12]
-        mov     ecx,[ebx+4]
-        shl     eax,1
-        rcl     edx,1
-        rcl     ecx,1
-        shl     eax,1
-        rcl     edx,1
-        rcl     ecx,1
-        add     eax,[ebx+8]
-        adc     edx,[ebx+12]
-        adc     ecx,[ebx+4]
-        shl     eax,1
-        rcl     edx,1
-        rcl     ecx,1
-        mov     [ebx+8],eax
-        mov     [ebx+12],edx
-        mov     [ebx+4],ecx
-    }
-}
-
-void DecAddInt32(DECIMAL* value, unsigned int i)
-{
-    LIMITED_METHOD_CONTRACT
-
-    _asm {
-        mov     edx,value
-        mov     eax,i
-        add     dword ptr [edx+8],eax
-        adc     dword ptr [edx+12],0
-        adc     dword ptr [edx+4],0
-    }
-}
-
-#pragma warning(default:4035)
-        
-#else // !(defined(_TARGET_X86_)
-
-unsigned int D32DivMod1E9(unsigned int hi32, ULONG* lo32)
-{
-    LIMITED_METHOD_CONTRACT
-    _ASSERTE(lo32 != NULL);
-
-    unsigned __int64 n = (unsigned __int64)hi32 << 32 | *lo32;
-    *lo32 = (unsigned int)(n / 1000000000);
-    return (unsigned int)(n % 1000000000);
-}
-
-unsigned int DecDivMod1E9(DECIMAL* value)
-{
-    WRAPPER_NO_CONTRACT
-    _ASSERTE(value != NULL);
-
-    return D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0,
-        &DECIMAL_HI32(*value)), &DECIMAL_MID32(*value)), &DECIMAL_LO32(*value));
-}
-
-void DecShiftLeft(DECIMAL* value)
-{
-    LIMITED_METHOD_CONTRACT
-    _ASSERTE(value != NULL);
-
-    unsigned int c0 = DECIMAL_LO32(*value) & 0x80000000? 1: 0;
-    unsigned int c1 = DECIMAL_MID32(*value) & 0x80000000? 1: 0;
-    DECIMAL_LO32(*value) <<= 1;
-    DECIMAL_MID32(*value) = DECIMAL_MID32(*value) << 1 | c0;
-    DECIMAL_HI32(*value) = DECIMAL_HI32(*value) << 1 | c1;
-}
-
-int D32AddCarry(ULONG* value, unsigned int i)
-{
-    LIMITED_METHOD_CONTRACT
-    _ASSERTE(value != NULL);
-
-    unsigned int v = *value;
-    unsigned int sum = v + i;
-    *value = sum;
-    return sum < v || sum < i? 1: 0;
-}
-
-void DecAdd(DECIMAL* value, DECIMAL* d)
-{
-    WRAPPER_NO_CONTRACT
-    _ASSERTE(value != NULL && d != NULL);
-
-    if (D32AddCarry(&DECIMAL_LO32(*value), DECIMAL_LO32(*d))) {
-        if (D32AddCarry(&DECIMAL_MID32(*value), 1)) {
-            D32AddCarry(&DECIMAL_HI32(*value), 1);
-        }
-    }
-    if (D32AddCarry(&DECIMAL_MID32(*value), DECIMAL_MID32(*d))) {
-        D32AddCarry(&DECIMAL_HI32(*value), 1);
-    }
-    D32AddCarry(&DECIMAL_HI32(*value), DECIMAL_HI32(*d));
-}
-
-void DecMul10(DECIMAL* value)
-{
-    WRAPPER_NO_CONTRACT
-    _ASSERTE(value != NULL);
-
-    DECIMAL d = *value;
-    DecShiftLeft(value);
-    DecShiftLeft(value);
-    DecAdd(value, &d);
-    DecShiftLeft(value);
-}
-
-void DecAddInt32(DECIMAL* value, unsigned int i)
-{
-    WRAPPER_NO_CONTRACT
-    _ASSERTE(value != NULL);
-
-    if (D32AddCarry(&DECIMAL_LO32(*value), i)) {
-        if (D32AddCarry(&DECIMAL_MID32(*value), 1)) {
-            D32AddCarry(&DECIMAL_HI32(*value), 1);
-        }
-    }
-}
-
-#endif
-
-/***
-* 
-*  Decimal Code ported from OleAut32
-* 
-***********************************************************************/
-
-// This OleAut code is only used on 64-bit and rotor platforms. It is desiriable to continue
-// to call the OleAut routines in X86 because of the performance of the hand-tuned assembly 
-// code and because there are currently no inconsistencies in behavior accross platforms.
-
-#ifndef UInt32x32To64
-#define UInt32x32To64(a, b) ((DWORDLONG)((DWORD)(a)) * (DWORDLONG)((DWORD)(b)))
-#endif
-
-typedef union {
-    DWORDLONG int64;  
-    struct {         
-#if BIGENDIAN
-      ULONG Hi;
-      ULONG Lo;
-#else            
-      ULONG Lo;
-      ULONG Hi;
-#endif           
-    } u;
-} SPLIT64;
-
-#define OVFL_MAX_1_HI   429496729
-#define DEC_SCALE_MAX   28
-#define POWER10_MAX 9
-
-#define OVFL_MAX_9_HI   4u
-#define OVFL_MAX_9_MID  1266874889u
-#define OVFL_MAX_9_LO   3047500985u
-
-#define OVFL_MAX_5_HI   42949
-
-
-const ULONG rgulPower10[POWER10_MAX+1] = {1, 10, 100, 1000, 10000, 100000, 1000000,
-                    10000000, 100000000, 1000000000};
-
-struct DECOVFL
-{
-    ULONG Hi;
-    ULONG Mid;
-    ULONG Lo;
-};
-
-const DECOVFL PowerOvfl[] = {
-// This is a table of the largest values that can be in the upper two
-// ULONGs of a 96-bit number that will not overflow when multiplied
-// by a given power.  For the upper word, this is a table of 
-// 2^32 / 10^n for 1 <= n <= 9.  For the lower word, this is the
-// remaining fraction part * 2^32.  2^32 = 4294967296.
-// 
-    { 429496729u, 2576980377u, 2576980377u }, // 10^1 remainder 0.6
-    { 42949672u,  4123168604u, 687194767u  }, // 10^2 remainder 0.16
-    { 4294967u,   1271310319u, 2645699854u }, // 10^3 remainder 0.616
-    { 429496u,    3133608139u, 694066715u  }, // 10^4 remainder 0.1616
-    { 42949u,     2890341191u, 2216890319u }, // 10^5 remainder 0.51616
-    { 4294u,      4154504685u, 2369172679u }, // 10^6 remainder 0.551616
-    { 429u,       2133437386u, 4102387834u }, // 10^7 remainder 0.9551616
-    { 42u,        4078814305u, 410238783u  }, // 10^8 remainder 0.09991616
-    { 4u,         1266874889u, 3047500985u }, // 10^9 remainder 0.709551616
-};
-
-
-/***
-* IncreaseScale
-*
-* Entry:
-*   rgulNum - Pointer to 96-bit number as array of ULONGs, least-sig first
-*   ulPwr   - Scale factor to multiply by
-*
-* Purpose:
-*   Multiply the two numbers.  The low 96 bits of the result overwrite
-*   the input.  The last 32 bits of the product are the return value.
-*
-* Exit:
-*   Returns highest 32 bits of product.
-*
-* Exceptions:
-*   None.
-*
-***********************************************************************/
-
-ULONG IncreaseScale(ULONG *rgulNum, ULONG ulPwr)
-{
-    LIMITED_METHOD_CONTRACT;
-    
-    SPLIT64   sdlTmp;
-
-    sdlTmp.int64 = UInt32x32To64(rgulNum[0], ulPwr);
-    rgulNum[0] = sdlTmp.u.Lo;
-    sdlTmp.int64 = UInt32x32To64(rgulNum[1], ulPwr) + sdlTmp.u.Hi;
-    rgulNum[1] = sdlTmp.u.Lo;
-    sdlTmp.int64 = UInt32x32To64(rgulNum[2], ulPwr) + sdlTmp.u.Hi;
-    rgulNum[2] = sdlTmp.u.Lo;
-    return sdlTmp.u.Hi;
-}
-
-
-/***
-* SearchScale
-*
-* Entry:
-*   ulResHi - Top ULONG of quotient
-*   ulResMid - Middle ULONG of quotient
-*   ulResLo - Bottom ULONG of quotient
-*   iScale  - Scale factor of quotient, range -DEC_SCALE_MAX to DEC_SCALE_MAX
-*
-* Purpose:
-*   Determine the max power of 10, <= 9, that the quotient can be scaled
-*   up by and still fit in 96 bits.
-*
-* Exit:
-*   Returns power of 10 to scale by, -1 if overflow error.
-*
-***********************************************************************/
-
-int SearchScale(ULONG ulResHi, ULONG ulResMid, ULONG ulResLo, int iScale)
-{
-    WRAPPER_NO_CONTRACT;
-
-    int   iCurScale;
-
-    // Quick check to stop us from trying to scale any more.
-    //
-    if (ulResHi > OVFL_MAX_1_HI || iScale >= DEC_SCALE_MAX) {
-      iCurScale = 0;
-      goto HaveScale;
-    }
-
-    if (iScale > DEC_SCALE_MAX - 9) {
-      // We can't scale by 10^9 without exceeding the max scale factor.
-      // See if we can scale to the max.  If not, we'll fall into
-      // standard search for scale factor.
-      //
-      iCurScale = DEC_SCALE_MAX - iScale;
-      if (ulResHi < PowerOvfl[iCurScale - 1].Hi)
-    goto HaveScale;
-
-      if (ulResHi == PowerOvfl[iCurScale - 1].Hi) {
-  UpperEq:
-        if (ulResMid > PowerOvfl[iCurScale - 1].Mid ||
-              (ulResMid == PowerOvfl[iCurScale - 1].Mid && ulResLo > PowerOvfl[iCurScale - 1].Lo)) {
-          iCurScale--;
-        }
-      goto HaveScale;
-      }
-    }
-    else if (ulResHi < OVFL_MAX_9_HI || (ulResHi == OVFL_MAX_9_HI && 
-      ulResMid < OVFL_MAX_9_MID) || (ulResHi == OVFL_MAX_9_HI && ulResMid == OVFL_MAX_9_MID && ulResLo <= OVFL_MAX_9_LO))
-      return 9;
-
-    // Search for a power to scale by < 9.  Do a binary search
-    // on PowerOvfl[].
-    //
-    iCurScale = 5;
-    if (ulResHi < OVFL_MAX_5_HI)
-      iCurScale = 7;
-    else if (ulResHi > OVFL_MAX_5_HI)
-      iCurScale = 3;
-    else
-      goto UpperEq;
-
-    // iCurScale is 3 or 7.
-    //
-    if (ulResHi < PowerOvfl[iCurScale - 1].Hi)
-      iCurScale++;
-    else if (ulResHi > PowerOvfl[iCurScale - 1].Hi)
-      iCurScale--;
-    else
-      goto UpperEq;
-
-    // iCurScale is 2, 4, 6, or 8.
-    //
-    // In all cases, we already found we could not use the power one larger.
-    // So if we can use this power, it is the biggest, and we're done.  If
-    // we can't use this power, the one below it is correct for all cases 
-    // unless it's 10^1 -- we might have to go to 10^0 (no scaling).
-    // 
-    if (ulResHi > PowerOvfl[iCurScale - 1].Hi)
-      iCurScale--;
-
-    if (ulResHi == PowerOvfl[iCurScale - 1].Hi)
-      goto UpperEq;
-
-HaveScale:
-    // iCurScale = largest power of 10 we can scale by without overflow, 
-    // iCurScale < 9.  See if this is enough to make scale factor 
-    // positive if it isn't already.
-    // 
-    if (iCurScale + iScale < 0)
-      iCurScale = -1;
-
-    return iCurScale;
-}
-
-//***********************************************************************
-//
-// Arithmetic Inlines
-//
-
-#define Div64by32(num, den) ((ULONG)((DWORDLONG)(num) / (ULONG)(den)))
-#define Mod64by32(num, den) ((ULONG)((DWORDLONG)(num) % (ULONG)(den)))
-
-inline DWORDLONG DivMod64by32(DWORDLONG num, ULONG den)
-{
-    WRAPPER_NO_CONTRACT;
-
-    SPLIT64  sdl;
-
-    sdl.u.Lo = Div64by32(num, den);
-    sdl.u.Hi = Mod64by32(num, den);
-    return sdl.int64;
-}
-
-/***
-* Div128By96
-*
-* Entry:
-*   rgulNum - Pointer to 128-bit dividend as array of ULONGs, least-sig first
-*   rgulDen - Pointer to 96-bit divisor.
-*
-* Purpose:
-*   Do partial divide, yielding 32-bit result and 96-bit remainder.
-*   Top divisor ULONG must be larger than top dividend ULONG.  This is
-*   assured in the initial call because the divisor is normalized
-*   and the dividend can't be.  In subsequent calls, the remainder
-*   is multiplied by 10^9 (max), so it can be no more than 1/4 of
-*   the divisor which is effectively multiplied by 2^32 (4 * 10^9).
-*
-* Exit:
-*   Remainder overwrites lower 96-bits of dividend.
-*   Returns quotient.
-*
-* Exceptions:
-*   None.
-*
-***********************************************************************/
-
-ULONG Div128By96(ULONG *rgulNum, ULONG *rgulDen)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    SPLIT64 sdlQuo;
-    SPLIT64 sdlNum;
-    SPLIT64 sdlProd1;
-    SPLIT64 sdlProd2;
-
-    sdlNum.u.Lo = rgulNum[0];
-    sdlNum.u.Hi = rgulNum[1];
-
-    if (rgulNum[3] == 0 && rgulNum[2] < rgulDen[2])
-      // Result is zero.  Entire dividend is remainder.
-      //
-      return 0;
-
-    // DivMod64by32 returns quotient in Lo, remainder in Hi.
-    //
-    sdlQuo.u.Lo = rgulNum[2];
-    sdlQuo.u.Hi = rgulNum[3];
-    sdlQuo.int64 = DivMod64by32(sdlQuo.int64, rgulDen[2]);
-
-    // Compute full remainder, rem = dividend - (quo * divisor).
-    //
-    sdlProd1.int64 = UInt32x32To64(sdlQuo.u.Lo, rgulDen[0]); // quo * lo divisor
-    sdlProd2.int64 = UInt32x32To64(sdlQuo.u.Lo, rgulDen[1]); // quo * mid divisor
-    sdlProd2.int64 += sdlProd1.u.Hi;
-    sdlProd1.u.Hi = sdlProd2.u.Lo;
-
-    sdlNum.int64 -= sdlProd1.int64;
-    rgulNum[2] = sdlQuo.u.Hi - sdlProd2.u.Hi; // sdlQuo.Hi is remainder
-
-    // Propagate carries
-    //
-    if (sdlNum.int64 > ~sdlProd1.int64) {
-      rgulNum[2]--;
-      if (rgulNum[2] >= ~sdlProd2.u.Hi)
-    goto NegRem;
-    }
-    else if (rgulNum[2] > ~sdlProd2.u.Hi) {
-NegRem:
-      // Remainder went negative.  Add divisor back in until it's positive,
-      // a max of 2 times.
-      //
-      sdlProd1.u.Lo = rgulDen[0];
-      sdlProd1.u.Hi = rgulDen[1];
-
-      for (;;) {
-    sdlQuo.u.Lo--;
-    sdlNum.int64 += sdlProd1.int64;
-    rgulNum[2] += rgulDen[2];
-
-    if (sdlNum.int64 < sdlProd1.int64) {
-      // Detected carry. Check for carry out of top
-      // before adding it in.
-      //
-      if (rgulNum[2]++ < rgulDen[2])
-        break;
-    }
-    if (rgulNum[2] < rgulDen[2])
-      break; // detected carry
-      }
-    }
-
-    rgulNum[0] = sdlNum.u.Lo;
-    rgulNum[1] = sdlNum.u.Hi;
-    return sdlQuo.u.Lo;
-}
-
-
-
-/***
-* Div96By32
-*
-* Entry:
-*   rgulNum - Pointer to 96-bit dividend as array of ULONGs, least-sig first
-*   ulDen   - 32-bit divisor.
-*
-* Purpose:
-*   Do full divide, yielding 96-bit result and 32-bit remainder.
-*
-* Exit:
-*   Quotient overwrites dividend.
-*   Returns remainder.
-*
-* Exceptions:
-*   None.
-*
-***********************************************************************/
-
-ULONG Div96By32(ULONG *rgulNum, ULONG ulDen)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    SPLIT64  sdlTmp;
-
-    sdlTmp.u.Hi = 0;
-
-    if (rgulNum[2] != 0)
-      goto Div3Word;
-
-    if (rgulNum[1] >= ulDen)
-      goto Div2Word;
-
-    sdlTmp.u.Hi = rgulNum[1];
-    rgulNum[1] = 0;
-    goto Div1Word;
-
-Div3Word:
-    sdlTmp.u.Lo = rgulNum[2];
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen);
-    rgulNum[2] = sdlTmp.u.Lo;
-Div2Word:
-    sdlTmp.u.Lo = rgulNum[1];
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen);
-    rgulNum[1] = sdlTmp.u.Lo;
-Div1Word:
-    sdlTmp.u.Lo = rgulNum[0];
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen);
-    rgulNum[0] = sdlTmp.u.Lo;
-    return sdlTmp.u.Hi;
-}
-
-
-/***
-* Div96By64
-*
-* Entry:
-*   rgulNum - Pointer to 96-bit dividend as array of ULONGs, least-sig first
-*   sdlDen  - 64-bit divisor.
-*
-* Purpose:
-*   Do partial divide, yielding 32-bit result and 64-bit remainder.
-*   Divisor must be larger than upper 64 bits of dividend.
-*
-* Exit:
-*   Remainder overwrites lower 64-bits of dividend.
-*   Returns quotient.
-*
-* Exceptions:
-*   None.
-*
-***********************************************************************/
-
-ULONG Div96By64(ULONG *rgulNum, SPLIT64 sdlDen)
-{
-    LIMITED_METHOD_CONTRACT;
-    
-    SPLIT64 sdlQuo;
-    SPLIT64 sdlNum;
-    SPLIT64 sdlProd;
-
-    sdlNum.u.Lo = rgulNum[0];
-
-    if (rgulNum[2] >= sdlDen.u.Hi) {
-      // Divide would overflow.  Assume a quotient of 2^32, and set
-      // up remainder accordingly.  Then jump to loop which reduces
-      // the quotient.
-      //
-      sdlNum.u.Hi = rgulNum[1] - sdlDen.u.Lo;
-      sdlQuo.u.Lo = 0;
-      goto NegRem;
-    }
-
-    // Hardware divide won't overflow
-    //
-    if (rgulNum[2] == 0 && rgulNum[1] < sdlDen.u.Hi)
-      // Result is zero.  Entire dividend is remainder.
-      //
-      return 0;
-
-    // DivMod64by32 returns quotient in Lo, remainder in Hi.
-    //
-    sdlQuo.u.Lo = rgulNum[1];
-    sdlQuo.u.Hi = rgulNum[2];
-    sdlQuo.int64 = DivMod64by32(sdlQuo.int64, sdlDen.u.Hi);
-    sdlNum.u.Hi = sdlQuo.u.Hi; // remainder
-
-    // Compute full remainder, rem = dividend - (quo * divisor).
-    //
-    sdlProd.int64 = UInt32x32To64(sdlQuo.u.Lo, sdlDen.u.Lo); // quo * lo divisor
-    sdlNum.int64 -= sdlProd.int64;
-
-    if (sdlNum.int64 > ~sdlProd.int64) {
-NegRem:
-      // Remainder went negative.  Add divisor back in until it's positive,
-      // a max of 2 times.
-      //
-      do {
-    sdlQuo.u.Lo--;
-    sdlNum.int64 += sdlDen.int64;
-      }while (sdlNum.int64 >= sdlDen.int64);
-    }
-
-    rgulNum[0] = sdlNum.u.Lo;
-    rgulNum[1] = sdlNum.u.Hi;
-    return sdlQuo.u.Lo;
-}
-
-// Add a 32 bit unsigned long to an array of 3 unsigned longs representing a 96 integer
-// Returns FALSE if there is an overflow
-BOOL Add32To96(ULONG *rgulNum, ULONG ulValue) {
-    rgulNum[0] += ulValue;
-    if (rgulNum[0] < ulValue) {
-        if (++rgulNum[1] == 0) {                
-            if (++rgulNum[2] == 0) {                
-                return FALSE;
-            }            
-        }
-    }
-    return TRUE;
-}
-
-// Adjust the quotient to deal with an overflow. We need to divide by 10, 
-// feed in the high bit to undo the overflow and then round as required, 
-void OverflowUnscale(ULONG *rgulQuo, BOOL fRemainder) {
-    LIMITED_METHOD_CONTRACT;
-
-    SPLIT64  sdlTmp;
-
-    // We have overflown, so load the high bit with a one.
-    sdlTmp.u.Hi = 1u;
-    sdlTmp.u.Lo = rgulQuo[2];
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10u);
-    rgulQuo[2] = sdlTmp.u.Lo;
-    sdlTmp.u.Lo = rgulQuo[1];
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10u);
-    rgulQuo[1] = sdlTmp.u.Lo;
-    sdlTmp.u.Lo = rgulQuo[0];
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10u);
-    rgulQuo[0] = sdlTmp.u.Lo;
-    // The remainder is the last digit that does not fit, so we can use it to work out if we need to round up
-    if ((sdlTmp.u.Hi > 5) || ((sdlTmp.u.Hi == 5) && ( fRemainder || (rgulQuo[0] & 1)))) {
-        Add32To96(rgulQuo, 1u);
-    }
-}
-
-
-
-//**********************************************************************
-//
-// VarDecDiv - Decimal Divide
-//
-//**********************************************************************
-
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
-#endif
-
-FCIMPL2(void, COMDecimal::DoDivideThrow, DECIMAL * pdecL, DECIMAL * pdecR)
-{
-    FCALL_CONTRACT;
-
-    ULONG   rgulQuo[3];
-    ULONG   rgulQuoSave[3];
-    ULONG   rgulRem[4];
-    ULONG   rgulDivisor[3];
-    ULONG   ulPwr;
-    ULONG   ulTmp;
-    ULONG   ulTmp1;
-    SPLIT64 sdlTmp;
-    SPLIT64 sdlDivisor;
-    int     iScale;
-    int     iCurScale;
-    BOOL    fUnscale;
-
-    iScale = DECIMAL_SCALE(*pdecL) - DECIMAL_SCALE(*pdecR);
-    fUnscale = FALSE;
-    rgulDivisor[0] = DECIMAL_LO32(*pdecR);
-    rgulDivisor[1] = DECIMAL_MID32(*pdecR);
-    rgulDivisor[2] = DECIMAL_HI32(*pdecR);
-
-    if (rgulDivisor[1] == 0 && rgulDivisor[2] == 0) {
-      // Divisor is only 32 bits.  Easy divide.
-      //
-      if (rgulDivisor[0] == 0)
-        FCThrowVoid(kDivideByZeroException);
-
-      rgulQuo[0] = DECIMAL_LO32(*pdecL);
-      rgulQuo[1] = DECIMAL_MID32(*pdecL);
-      rgulQuo[2] = DECIMAL_HI32(*pdecL);
-      rgulRem[0] = Div96By32(rgulQuo, rgulDivisor[0]);
-
-      for (;;) {
-    if (rgulRem[0] == 0) {
-      if (iScale < 0) {
-        iCurScale = min(9, -iScale);
-        goto HaveScale;
-      }
-      break;
-    }
-    // We need to unscale if and only if we have a non-zero remainder
-    fUnscale = TRUE;
-
-    // We have computed a quotient based on the natural scale 
-    // ( <dividend scale> - <divisor scale> ).  We have a non-zero 
-    // remainder, so now we should increase the scale if possible to 
-    // include more quotient bits.
-    // 
-    // If it doesn't cause overflow, we'll loop scaling by 10^9 and 
-    // computing more quotient bits as long as the remainder stays 
-    // non-zero.  If scaling by that much would cause overflow, we'll 
-    // drop out of the loop and scale by as much as we can.
-    // 
-    // Scaling by 10^9 will overflow if rgulQuo[2].rgulQuo[1] >= 2^32 / 10^9 
-    // = 4.294 967 296.  So the upper limit is rgulQuo[2] == 4 and 
-    // rgulQuo[1] == 0.294 967 296 * 2^32 = 1,266,874,889.7+.  Since 
-    // quotient bits in rgulQuo[0] could be all 1's, then 1,266,874,888 
-    // is the largest value in rgulQuo[1] (when rgulQuo[2] == 4) that is 
-    // assured not to overflow.
-    // 
-    iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale);
-    if (iCurScale == 0) {
-      // No more scaling to be done, but remainder is non-zero.
-      // Round quotient.
-      //
-      ulTmp = rgulRem[0] << 1;
-      if (ulTmp < rgulRem[0] || (ulTmp >= rgulDivisor[0] &&
-          (ulTmp > rgulDivisor[0] || (rgulQuo[0] & 1)))) {
-RoundUp:
-        if (!Add32To96(rgulQuo, 1)) {
-            if (iScale == 0) {
-                FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-            }
-            iScale--;
-            OverflowUnscale(rgulQuo, TRUE);
-            break;
-        }      
-      }
-      break;
-    }
-
-    if (iCurScale < 0) {
-      FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-    }
-
-HaveScale:
-    ulPwr = rgulPower10[iCurScale];
-    iScale += iCurScale;
-
-    if (IncreaseScale(rgulQuo, ulPwr) != 0) {
-      FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-    }
-
-
-    sdlTmp.int64 = DivMod64by32(UInt32x32To64(rgulRem[0], ulPwr), rgulDivisor[0]);
-    rgulRem[0] = sdlTmp.u.Hi;
-
-    if (!Add32To96(rgulQuo, sdlTmp.u.Lo)) {
-        if (iScale == 0) {
-            FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-        }
-        iScale--;
-        OverflowUnscale(rgulQuo, (rgulRem[0] != 0));
-        break;
-    }
-      } // for (;;)
-    }
-    else {
-      // Divisor has bits set in the upper 64 bits.
-      //
-      // Divisor must be fully normalized (shifted so bit 31 of the most 
-      // significant ULONG is 1).  Locate the MSB so we know how much to 
-      // normalize by.  The dividend will be shifted by the same amount so 
-      // the quotient is not changed.
-      //
-      if (rgulDivisor[2] == 0)
-    ulTmp = rgulDivisor[1];
-      else
-    ulTmp = rgulDivisor[2];
-
-      iCurScale = 0;
-      if (!(ulTmp & 0xFFFF0000)) {
-    iCurScale += 16;
-    ulTmp <<= 16;
-      }
-      if (!(ulTmp & 0xFF000000)) {
-    iCurScale += 8;
-    ulTmp <<= 8;
-      }
-      if (!(ulTmp & 0xF0000000)) {
-    iCurScale += 4;
-    ulTmp <<= 4;
-      }
-      if (!(ulTmp & 0xC0000000)) {
-    iCurScale += 2;
-    ulTmp <<= 2;
-      }
-      if (!(ulTmp & 0x80000000)) {
-    iCurScale++;
-    ulTmp <<= 1;
-      }
-    
-      // Shift both dividend and divisor left by iCurScale.
-      // 
-      sdlTmp.int64 = DECIMAL_LO64_GET(*pdecL) << iCurScale;
-      rgulRem[0] = sdlTmp.u.Lo;
-      rgulRem[1] = sdlTmp.u.Hi;
-      sdlTmp.u.Lo = DECIMAL_MID32(*pdecL);
-      sdlTmp.u.Hi = DECIMAL_HI32(*pdecL);
-      sdlTmp.int64 <<= iCurScale;
-      rgulRem[2] = sdlTmp.u.Hi;
-      rgulRem[3] = (DECIMAL_HI32(*pdecL) >> (31 - iCurScale)) >> 1;
-
-      sdlDivisor.u.Lo = rgulDivisor[0];
-      sdlDivisor.u.Hi = rgulDivisor[1];
-      sdlDivisor.int64 <<= iCurScale;
-
-      if (rgulDivisor[2] == 0) {
-    // Have a 64-bit divisor in sdlDivisor.  The remainder 
-    // (currently 96 bits spread over 4 ULONGs) will be < divisor.
-    // 
-    sdlTmp.u.Lo = rgulRem[2];
-    sdlTmp.u.Hi = rgulRem[3];
-
-    rgulQuo[2] = 0;
-    rgulQuo[1] = Div96By64(&rgulRem[1], sdlDivisor);
-    rgulQuo[0] = Div96By64(rgulRem, sdlDivisor);
-
-    for (;;) {
-      if ((rgulRem[0] | rgulRem[1]) == 0) {
-        if (iScale < 0) {
-          iCurScale = min(9, -iScale);
-          goto HaveScale64;
-        }
-        break;
-      }
-
-      // We need to unscale if and only if we have a non-zero remainder
-      fUnscale = TRUE;
-
-      // Remainder is non-zero.  Scale up quotient and remainder by 
-      // powers of 10 so we can compute more significant bits.
-      // 
-      iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale);
-      if (iCurScale == 0) {
-        // No more scaling to be done, but remainder is non-zero.
-        // Round quotient.
-        //
-        sdlTmp.u.Lo = rgulRem[0];
-        sdlTmp.u.Hi = rgulRem[1];
-        if (sdlTmp.u.Hi >= 0x80000000 || (sdlTmp.int64 <<= 1) > sdlDivisor.int64 ||
-        (sdlTmp.int64 == sdlDivisor.int64 && (rgulQuo[0] & 1)))
-          goto RoundUp;
-        break;
-      }
-
-      if (iCurScale < 0) {
-          FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-      }
-
-HaveScale64:
-      ulPwr = rgulPower10[iCurScale];
-      iScale += iCurScale;
-
-      if (IncreaseScale(rgulQuo, ulPwr) != 0) {
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-      }
-
-
-      rgulRem[2] = 0;  // rem is 64 bits, IncreaseScale uses 96
-      IncreaseScale(rgulRem, ulPwr);
-      ulTmp = Div96By64(rgulRem, sdlDivisor);
-      if (!Add32To96(rgulQuo, ulTmp)) {
-        if (iScale == 0) {
-            FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-        }
-        iScale--;
-        OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0));
-        break;
-      }      
-
-    } // for (;;)
-      }
-      else {
-    // Have a 96-bit divisor in rgulDivisor[].
-    //
-    // Start by finishing the shift left by iCurScale.
-    //
-    sdlTmp.u.Lo = rgulDivisor[1];
-    sdlTmp.u.Hi = rgulDivisor[2];
-    sdlTmp.int64 <<= iCurScale;
-    rgulDivisor[0] = sdlDivisor.u.Lo;
-    rgulDivisor[1] = sdlDivisor.u.Hi;
-    rgulDivisor[2] = sdlTmp.u.Hi;
-
-    // The remainder (currently 96 bits spread over 4 ULONGs) 
-    // will be < divisor.
-    // 
-    rgulQuo[2] = 0;
-    rgulQuo[1] = 0;
-    rgulQuo[0] = Div128By96(rgulRem, rgulDivisor);
-
-    for (;;) {
-      if ((rgulRem[0] | rgulRem[1] | rgulRem[2]) == 0) {
-        if (iScale < 0) {
-          iCurScale = min(9, -iScale);
-          goto HaveScale96;
-        }
-        break;
-      }
-
-      // We need to unscale if and only if we have a non-zero remainder
-      fUnscale = TRUE;
-
-      // Remainder is non-zero.  Scale up quotient and remainder by 
-      // powers of 10 so we can compute more significant bits.
-      // 
-      iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale);
-      if (iCurScale == 0) {
-        // No more scaling to be done, but remainder is non-zero.
-        // Round quotient.
-        //
-        if (rgulRem[2] >= 0x80000000)
-          goto RoundUp;
-
-        ulTmp = rgulRem[0] > 0x80000000;
-        ulTmp1 = rgulRem[1] > 0x80000000;
-        rgulRem[0] <<= 1;
-        rgulRem[1] = (rgulRem[1] << 1) + ulTmp;
-        rgulRem[2] = (rgulRem[2] << 1) + ulTmp1;
-
-        if (rgulRem[2] > rgulDivisor[2] || (rgulRem[2] == rgulDivisor[2] &&
-        (rgulRem[1] > rgulDivisor[1] || (rgulRem[1] == rgulDivisor[1] &&
-        (rgulRem[0] > rgulDivisor[0] || (rgulRem[0] == rgulDivisor[0] &&
-        (rgulQuo[0] & 1)))))))
-          goto RoundUp;
-        break;
-      }
-
-      if (iCurScale < 0) {
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-      }
-
-HaveScale96:
-      ulPwr = rgulPower10[iCurScale];
-      iScale += iCurScale;
-
-      if (IncreaseScale(rgulQuo, ulPwr) != 0) {
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-      }
-
-      rgulRem[3] = IncreaseScale(rgulRem, ulPwr);
-      ulTmp = Div128By96(rgulRem, rgulDivisor);
-      if (!Add32To96(rgulQuo, ulTmp)) {
-        if (iScale == 0) {
-          FCThrowResVoid(kOverflowException, W("Overflow_Decimal"));
-        }
-        iScale--;
-        OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0 || rgulRem[2] != 0 || rgulRem[3] != 0));
-        break;
-      }      
-
-    } // for (;;)
-      }
-    }
-
-    // We need to unscale if and only if we have a non-zero remainder
-    if (fUnscale) {
-        // Try extracting any extra powers of 10 we may have 
-        // added.  We do this by trying to divide out 10^8, 10^4, 10^2, and 10^1.
-        // If a division by one of these powers returns a zero remainder, then
-        // we keep the quotient.  If the remainder is not zero, then we restore
-        // the previous value.
-        // 
-        // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10
-        // we can extract.  We use this as a quick test on whether to try a
-        // given power.
-        // 
-        while ((rgulQuo[0] & 0xFF) == 0 && iScale >= 8) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 100000000) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 8;
-            }
-            else
-            break;
-        }
-
-        if ((rgulQuo[0] & 0xF) == 0 && iScale >= 4) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 10000) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 4;
-            }
-        }
-
-        if ((rgulQuo[0] & 3) == 0 && iScale >= 2) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 100) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 2;
-            }
-        }
-
-        if ((rgulQuo[0] & 1) == 0 && iScale >= 1) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 10) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 1;
-            }
-        }
-    }
-
-    DECIMAL_SIGN(*pdecL) = DECIMAL_SIGN(*pdecL) ^ DECIMAL_SIGN(*pdecR);
-    DECIMAL_HI32(*pdecL) = rgulQuo[2];
-    DECIMAL_MID32(*pdecL) = rgulQuo[1];
-    DECIMAL_LO32(*pdecL) = rgulQuo[0];
-    DECIMAL_SCALE(*pdecL) = (BYTE)iScale;
-
-    pdecL->wReserved = 0;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
-
-FCIMPL3(void, COMDecimal::DoDivide, DECIMAL * pdecL, DECIMAL * pdecR, CLR_BOOL * overflowed)
-{
-    FCALL_CONTRACT;
-
-    ULONG   rgulQuo[3];
-    ULONG   rgulQuoSave[3];
-    ULONG   rgulRem[4];
-    ULONG   rgulDivisor[3];
-    ULONG   ulPwr;
-    ULONG   ulTmp;
-    ULONG   ulTmp1;
-    SPLIT64 sdlTmp;
-    SPLIT64 sdlDivisor;
-    int     iScale;
-    int     iCurScale;
-    BOOL    fUnscale;
-
-    iScale = DECIMAL_SCALE(*pdecL) - DECIMAL_SCALE(*pdecR);
-    fUnscale = FALSE;
-    rgulDivisor[0] = DECIMAL_LO32(*pdecR);
-    rgulDivisor[1] = DECIMAL_MID32(*pdecR);
-    rgulDivisor[2] = DECIMAL_HI32(*pdecR);
-
-    if (rgulDivisor[1] == 0 && rgulDivisor[2] == 0) {
-      // Divisor is only 32 bits.  Easy divide.
-      //
-      if (rgulDivisor[0] == 0)
-        FCThrowVoid(kDivideByZeroException);
-
-      rgulQuo[0] = DECIMAL_LO32(*pdecL);
-      rgulQuo[1] = DECIMAL_MID32(*pdecL);
-      rgulQuo[2] = DECIMAL_HI32(*pdecL);
-      rgulRem[0] = Div96By32(rgulQuo, rgulDivisor[0]);
-
-      for (;;) {
-    if (rgulRem[0] == 0) {
-      if (iScale < 0) {
-        iCurScale = min(9, -iScale);
-        goto HaveScale;
-      }
-      break;
-    }
-    // We need to unscale if and only if we have a non-zero remainder
-    fUnscale = TRUE;
-
-    // We have computed a quotient based on the natural scale 
-    // ( <dividend scale> - <divisor scale> ).  We have a non-zero 
-    // remainder, so now we should increase the scale if possible to 
-    // include more quotient bits.
-    // 
-    // If it doesn't cause overflow, we'll loop scaling by 10^9 and 
-    // computing more quotient bits as long as the remainder stays 
-    // non-zero.  If scaling by that much would cause overflow, we'll 
-    // drop out of the loop and scale by as much as we can.
-    // 
-    // Scaling by 10^9 will overflow if rgulQuo[2].rgulQuo[1] >= 2^32 / 10^9 
-    // = 4.294 967 296.  So the upper limit is rgulQuo[2] == 4 and 
-    // rgulQuo[1] == 0.294 967 296 * 2^32 = 1,266,874,889.7+.  Since 
-    // quotient bits in rgulQuo[0] could be all 1's, then 1,266,874,888 
-    // is the largest value in rgulQuo[1] (when rgulQuo[2] == 4) that is 
-    // assured not to overflow.
-    // 
-    iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale);
-    if (iCurScale == 0) {
-      // No more scaling to be done, but remainder is non-zero.
-      // Round quotient.
-      //
-      ulTmp = rgulRem[0] << 1;
-      if (ulTmp < rgulRem[0] || (ulTmp >= rgulDivisor[0] &&
-          (ulTmp > rgulDivisor[0] || (rgulQuo[0] & 1)))) {
-RoundUp:
-        if (!Add32To96(rgulQuo, 1)) {
-            if (iScale == 0) {
-                *overflowed = true;
-                FC_GC_POLL();
-                return;
-            }
-            iScale--;
-            OverflowUnscale(rgulQuo, TRUE);
-            break;
-        }      
-      }
-      break;
-    }
-
-    if (iCurScale < 0) {
-        *overflowed = true;
-        FC_GC_POLL();
-        return;
-    }
-
-HaveScale:
-    ulPwr = rgulPower10[iCurScale];
-    iScale += iCurScale;
-
-    if (IncreaseScale(rgulQuo, ulPwr) != 0) {
-        *overflowed = true;
-        FC_GC_POLL();
-        return;
-    }
-
-
-    sdlTmp.int64 = DivMod64by32(UInt32x32To64(rgulRem[0], ulPwr), rgulDivisor[0]);
-    rgulRem[0] = sdlTmp.u.Hi;
-
-    if (!Add32To96(rgulQuo, sdlTmp.u.Lo)) {
-        if (iScale == 0) {
-            *overflowed = true;
-            FC_GC_POLL();
-            return;
-        }
-        iScale--;
-        OverflowUnscale(rgulQuo, (rgulRem[0] != 0));
-        break;
-    }
-      } // for (;;)
-    }
-    else {
-      // Divisor has bits set in the upper 64 bits.
-      //
-      // Divisor must be fully normalized (shifted so bit 31 of the most 
-      // significant ULONG is 1).  Locate the MSB so we know how much to 
-      // normalize by.  The dividend will be shifted by the same amount so 
-      // the quotient is not changed.
-      //
-      if (rgulDivisor[2] == 0)
-    ulTmp = rgulDivisor[1];
-      else
-    ulTmp = rgulDivisor[2];
-
-      iCurScale = 0;
-      if (!(ulTmp & 0xFFFF0000)) {
-    iCurScale += 16;
-    ulTmp <<= 16;
-      }
-      if (!(ulTmp & 0xFF000000)) {
-    iCurScale += 8;
-    ulTmp <<= 8;
-      }
-      if (!(ulTmp & 0xF0000000)) {
-    iCurScale += 4;
-    ulTmp <<= 4;
-      }
-      if (!(ulTmp & 0xC0000000)) {
-    iCurScale += 2;
-    ulTmp <<= 2;
-      }
-      if (!(ulTmp & 0x80000000)) {
-    iCurScale++;
-    ulTmp <<= 1;
-      }
-    
-      // Shift both dividend and divisor left by iCurScale.
-      // 
-      sdlTmp.int64 = DECIMAL_LO64_GET(*pdecL) << iCurScale;
-      rgulRem[0] = sdlTmp.u.Lo;
-      rgulRem[1] = sdlTmp.u.Hi;
-      sdlTmp.u.Lo = DECIMAL_MID32(*pdecL);
-      sdlTmp.u.Hi = DECIMAL_HI32(*pdecL);
-      sdlTmp.int64 <<= iCurScale;
-      rgulRem[2] = sdlTmp.u.Hi;
-      rgulRem[3] = (DECIMAL_HI32(*pdecL) >> (31 - iCurScale)) >> 1;
-
-      sdlDivisor.u.Lo = rgulDivisor[0];
-      sdlDivisor.u.Hi = rgulDivisor[1];
-      sdlDivisor.int64 <<= iCurScale;
-
-      if (rgulDivisor[2] == 0) {
-    // Have a 64-bit divisor in sdlDivisor.  The remainder 
-    // (currently 96 bits spread over 4 ULONGs) will be < divisor.
-    // 
-    sdlTmp.u.Lo = rgulRem[2];
-    sdlTmp.u.Hi = rgulRem[3];
-
-    rgulQuo[2] = 0;
-    rgulQuo[1] = Div96By64(&rgulRem[1], sdlDivisor);
-    rgulQuo[0] = Div96By64(rgulRem, sdlDivisor);
-
-    for (;;) {
-      if ((rgulRem[0] | rgulRem[1]) == 0) {
-        if (iScale < 0) {
-          iCurScale = min(9, -iScale);
-          goto HaveScale64;
-        }
-        break;
-      }
-
-      // We need to unscale if and only if we have a non-zero remainder
-      fUnscale = TRUE;
-
-      // Remainder is non-zero.  Scale up quotient and remainder by 
-      // powers of 10 so we can compute more significant bits.
-      // 
-      iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale);
-      if (iCurScale == 0) {
-        // No more scaling to be done, but remainder is non-zero.
-        // Round quotient.
-        //
-        sdlTmp.u.Lo = rgulRem[0];
-        sdlTmp.u.Hi = rgulRem[1];
-        if (sdlTmp.u.Hi >= 0x80000000 || (sdlTmp.int64 <<= 1) > sdlDivisor.int64 ||
-        (sdlTmp.int64 == sdlDivisor.int64 && (rgulQuo[0] & 1)))
-          goto RoundUp;
-        break;
-      }
-
-      if (iCurScale < 0) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-      }
-
-HaveScale64:
-      ulPwr = rgulPower10[iCurScale];
-      iScale += iCurScale;
-
-      if (IncreaseScale(rgulQuo, ulPwr) != 0) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-      }
-
-
-      rgulRem[2] = 0;  // rem is 64 bits, IncreaseScale uses 96
-      IncreaseScale(rgulRem, ulPwr);
-      ulTmp = Div96By64(rgulRem, sdlDivisor);
-      if (!Add32To96(rgulQuo, ulTmp)) {
-        if (iScale == 0) {
-            *overflowed = true;
-            FC_GC_POLL();
-            return;
-        }
-        iScale--;
-        OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0));
-        break;
-      }      
-
-    } // for (;;)
-      }
-      else {
-    // Have a 96-bit divisor in rgulDivisor[].
-    //
-    // Start by finishing the shift left by iCurScale.
-    //
-    sdlTmp.u.Lo = rgulDivisor[1];
-    sdlTmp.u.Hi = rgulDivisor[2];
-    sdlTmp.int64 <<= iCurScale;
-    rgulDivisor[0] = sdlDivisor.u.Lo;
-    rgulDivisor[1] = sdlDivisor.u.Hi;
-    rgulDivisor[2] = sdlTmp.u.Hi;
-
-    // The remainder (currently 96 bits spread over 4 ULONGs) 
-    // will be < divisor.
-    // 
-    rgulQuo[2] = 0;
-    rgulQuo[1] = 0;
-    rgulQuo[0] = Div128By96(rgulRem, rgulDivisor);
-
-    for (;;) {
-      if ((rgulRem[0] | rgulRem[1] | rgulRem[2]) == 0) {
-        if (iScale < 0) {
-          iCurScale = min(9, -iScale);
-          goto HaveScale96;
-        }
-        break;
-      }
-
-      // We need to unscale if and only if we have a non-zero remainder
-      fUnscale = TRUE;
-
-      // Remainder is non-zero.  Scale up quotient and remainder by 
-      // powers of 10 so we can compute more significant bits.
-      // 
-      iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale);
-      if (iCurScale == 0) {
-        // No more scaling to be done, but remainder is non-zero.
-        // Round quotient.
-        //
-        if (rgulRem[2] >= 0x80000000)
-          goto RoundUp;
-
-        ulTmp = rgulRem[0] > 0x80000000;
-        ulTmp1 = rgulRem[1] > 0x80000000;
-        rgulRem[0] <<= 1;
-        rgulRem[1] = (rgulRem[1] << 1) + ulTmp;
-        rgulRem[2] = (rgulRem[2] << 1) + ulTmp1;
-
-        if (rgulRem[2] > rgulDivisor[2] || (rgulRem[2] == rgulDivisor[2] &&
-        (rgulRem[1] > rgulDivisor[1] || (rgulRem[1] == rgulDivisor[1] &&
-        (rgulRem[0] > rgulDivisor[0] || (rgulRem[0] == rgulDivisor[0] &&
-        (rgulQuo[0] & 1)))))))
-          goto RoundUp;
-        break;
-      }
-
-      if (iCurScale < 0) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-      }
-
-HaveScale96:
-      ulPwr = rgulPower10[iCurScale];
-      iScale += iCurScale;
-
-      if (IncreaseScale(rgulQuo, ulPwr) != 0) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-      }
-
-      rgulRem[3] = IncreaseScale(rgulRem, ulPwr);
-      ulTmp = Div128By96(rgulRem, rgulDivisor);
-      if (!Add32To96(rgulQuo, ulTmp)) {
-        if (iScale == 0) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-        }
-        iScale--;
-        OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0 || rgulRem[2] != 0 || rgulRem[3] != 0));
-        break;
-      }      
-
-    } // for (;;)
-      }
-    }
-
-    // We need to unscale if and only if we have a non-zero remainder
-    if (fUnscale) {
-        // Try extracting any extra powers of 10 we may have 
-        // added.  We do this by trying to divide out 10^8, 10^4, 10^2, and 10^1.
-        // If a division by one of these powers returns a zero remainder, then
-        // we keep the quotient.  If the remainder is not zero, then we restore
-        // the previous value.
-        // 
-        // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10
-        // we can extract.  We use this as a quick test on whether to try a
-        // given power.
-        // 
-        while ((rgulQuo[0] & 0xFF) == 0 && iScale >= 8) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 100000000) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 8;
-            }
-            else
-            break;
-        }
-
-        if ((rgulQuo[0] & 0xF) == 0 && iScale >= 4) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 10000) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 4;
-            }
-        }
-
-        if ((rgulQuo[0] & 3) == 0 && iScale >= 2) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 100) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 2;
-            }
-        }
-
-        if ((rgulQuo[0] & 1) == 0 && iScale >= 1) {
-            rgulQuoSave[0] = rgulQuo[0];
-            rgulQuoSave[1] = rgulQuo[1];
-            rgulQuoSave[2] = rgulQuo[2];
-
-            if (Div96By32(rgulQuoSave, 10) == 0) {
-            rgulQuo[0] = rgulQuoSave[0];
-            rgulQuo[1] = rgulQuoSave[1];
-            rgulQuo[2] = rgulQuoSave[2];
-            iScale -= 1;
-            }
-        }
-    }
-
-    DECIMAL_SIGN(*pdecL) = DECIMAL_SIGN(*pdecL) ^ DECIMAL_SIGN(*pdecR);
-    DECIMAL_HI32(*pdecL) = rgulQuo[2];
-    DECIMAL_MID32(*pdecL) = rgulQuo[1];
-    DECIMAL_LO32(*pdecL) = rgulQuo[0];
-    DECIMAL_SCALE(*pdecL) = (BYTE)iScale;
-
-    pdecL->wReserved = 0;
-    *overflowed = false;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
-
-//**********************************************************************
-//
-// VarDecAdd - Decimal Addition
-// VarDecSub - Decimal Subtraction
-//
-//**********************************************************************
-
-static const ULONG ulTenToNine    = 1000000000;
-
-/***
-* ScaleResult
-*
-* Entry:
-*   rgulRes - Array of ULONGs with value, least-significant first.
-*   iHiRes  - Index of last non-zero value in rgulRes.
-*   iScale  - Scale factor for this value, range 0 - 2 * DEC_SCALE_MAX
-*
-* Purpose:
-*   See if we need to scale the result to fit it in 96 bits.
-*   Perform needed scaling.  Adjust scale factor accordingly.
-*
-* Exit:
-*   rgulRes updated in place, always 3 ULONGs.
-*   New scale factor returned, -1 if overflow error.
-*
-***********************************************************************/
-
-int ScaleResult(ULONG *rgulRes, int iHiRes, int iScale)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    int     iNewScale;
-    int     iCur;
-    ULONG   ulPwr;
-    ULONG   ulTmp;
-    ULONG   ulSticky;
-    SPLIT64 sdlTmp;
-
-    // See if we need to scale the result.  The combined scale must
-    // be <= DEC_SCALE_MAX and the upper 96 bits must be zero.
-    // 
-    // Start by figuring a lower bound on the scaling needed to make
-    // the upper 96 bits zero.  iHiRes is the index into rgulRes[]
-    // of the highest non-zero ULONG.
-    // 
-    iNewScale =   iHiRes * 32 - 64 - 1;
-    if (iNewScale > 0) {
-
-      // Find the MSB.
-      //
-      ulTmp = rgulRes[iHiRes];
-      if (!(ulTmp & 0xFFFF0000)) {
-    iNewScale -= 16;
-    ulTmp <<= 16;
-      }
-      if (!(ulTmp & 0xFF000000)) {
-    iNewScale -= 8;
-    ulTmp <<= 8;
-      }
-      if (!(ulTmp & 0xF0000000)) {
-    iNewScale -= 4;
-    ulTmp <<= 4;
-      }
-      if (!(ulTmp & 0xC0000000)) {
-    iNewScale -= 2;
-    ulTmp <<= 2;
-      }
-      if (!(ulTmp & 0x80000000)) {
-    iNewScale--;
-    ulTmp <<= 1;
-      }
-    
-      // Multiply bit position by log10(2) to figure it's power of 10.
-      // We scale the log by 256.  log(2) = .30103, * 256 = 77.  Doing this 
-      // with a multiply saves a 96-byte lookup table.  The power returned
-      // is <= the power of the number, so we must add one power of 10
-      // to make it's integer part zero after dividing by 256.
-      // 
-      // Note: the result of this multiplication by an approximation of
-      // log10(2) have been exhaustively checked to verify it gives the 
-      // correct result.  (There were only 95 to check...)
-      // 
-      iNewScale = ((iNewScale * 77) >> 8) + 1;
-
-      // iNewScale = min scale factor to make high 96 bits zero, 0 - 29.
-      // This reduces the scale factor of the result.  If it exceeds the
-      // current scale of the result, we'll overflow.
-      // 
-      if (iNewScale > iScale)
-    return -1;
-    }
-    else
-      iNewScale = 0;
-
-    // Make sure we scale by enough to bring the current scale factor
-    // into valid range.
-    //
-    if (iNewScale < iScale - DEC_SCALE_MAX)
-      iNewScale = iScale - DEC_SCALE_MAX;
-
-    if (iNewScale != 0) {
-      // Scale by the power of 10 given by iNewScale.  Note that this is 
-      // NOT guaranteed to bring the number within 96 bits -- it could 
-      // be 1 power of 10 short.
-      //
-      iScale -= iNewScale;
-      ulSticky = 0;
-      sdlTmp.u.Hi = 0; // initialize remainder
-
-      for (;;) {
-
-    ulSticky |= sdlTmp.u.Hi; // record remainder as sticky bit
-
-    if (iNewScale > POWER10_MAX)
-      ulPwr = ulTenToNine;
-    else
-      ulPwr = rgulPower10[iNewScale];
-
-    // Compute first quotient.
-    // DivMod64by32 returns quotient in Lo, remainder in Hi.
-    //
-    sdlTmp.int64 = DivMod64by32(rgulRes[iHiRes], ulPwr);
-    rgulRes[iHiRes] = sdlTmp.u.Lo;
-    iCur = iHiRes - 1;
-
-    if (iCur >= 0) {
-      // If first quotient was 0, update iHiRes.
-      //
-      if (sdlTmp.u.Lo == 0)
-        iHiRes--;
-
-      // Compute subsequent quotients.
-      //
-      do {
-        sdlTmp.u.Lo = rgulRes[iCur];
-        sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
-        rgulRes[iCur] = sdlTmp.u.Lo;
-        iCur--;
-      } while (iCur >= 0);
-
-    }
-
-    iNewScale -= POWER10_MAX;
-    if (iNewScale > 0)
-      continue; // scale some more
-
-    // If we scaled enough, iHiRes would be 2 or less.  If not,
-    // divide by 10 more.
-    //
-    if (iHiRes > 2) {
-      iNewScale = 1;
-      iScale--;
-      continue; // scale by 10
-    }
-
-    // Round final result.  See if remainder >= 1/2 of divisor.
-    // If remainder == 1/2 divisor, round up if odd or sticky bit set.
-    //
-    ulPwr >>= 1;  // power of 10 always even
-    if ( ulPwr <= sdlTmp.u.Hi && (ulPwr < sdlTmp.u.Hi ||
-        ((rgulRes[0] & 1) | ulSticky)) ) {
-      iCur = -1;
-      while (++rgulRes[++iCur] == 0);
-
-      if (iCur > 2) {
-        // The rounding caused us to carry beyond 96 bits. 
-        // Scale by 10 more.
-        //
-        iHiRes = iCur;
-        ulSticky = 0;  // no sticky bit
-        sdlTmp.u.Hi = 0; // or remainder
-        iNewScale = 1;
-        iScale--;
-        continue; // scale by 10
-      }
-    }
-
-    // We may have scaled it more than we planned.  Make sure the scale 
-    // factor hasn't gone negative, indicating overflow.
-    // 
-    if (iScale < 0)
-      return -1;
-
-    return iScale;
-      } // for(;;)
-    }
-    return iScale;
-}
-
-FCIMPL3(void, COMDecimal::DoAddSubThrow, DECIMAL * pdecL, DECIMAL * pdecR, UINT8 bSign)
-{
-    FCALL_CONTRACT;
-
-    ULONG     rgulNum[6];
-    ULONG     ulPwr;
-    int       iScale;
-    int       iHiProd;
-    int       iCur;
-    SPLIT64   sdlTmp;
-    DECIMAL   decRes;
-    DECIMAL   decTmp;
-    LPDECIMAL pdecTmp;
-    LPDECIMAL pdecLOriginal;
-
-    _ASSERTE(bSign == 0 || bSign == DECIMAL_NEG);
-
-    pdecLOriginal = pdecL;
-
-    bSign ^= (DECIMAL_SIGN(*pdecR) ^ DECIMAL_SIGN(*pdecL)) & DECIMAL_NEG;
-
-    if (DECIMAL_SCALE(*pdecR) == DECIMAL_SCALE(*pdecL)) {
-      // Scale factors are equal, no alignment necessary.
-      //
-      DECIMAL_SIGNSCALE(decRes) = DECIMAL_SIGNSCALE(*pdecL);
-
-AlignedAdd:
-      if (bSign) {
-    // Signs differ - subtract
-    //
-    DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) - DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) - DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) > DECIMAL_LO64_GET(*pdecL)) {
-      DECIMAL_HI32(decRes)--;
-      if (DECIMAL_HI32(decRes) >= DECIMAL_HI32(*pdecL))
-        goto SignFlip;
-    }
-    else if (DECIMAL_HI32(decRes) > DECIMAL_HI32(*pdecL)) {
-      // Got negative result.  Flip its sign.
-      // 
-SignFlip:
-      DECIMAL_LO64_SET(decRes, -(LONGLONG)DECIMAL_LO64_GET(decRes));
-      DECIMAL_HI32(decRes) = ~DECIMAL_HI32(decRes);
-      if (DECIMAL_LO64_GET(decRes) == 0)
-        DECIMAL_HI32(decRes)++;
-      DECIMAL_SIGN(decRes) ^= DECIMAL_NEG;
-    }
-
-      }
-      else {
-    // Signs are the same - add
-    //
-    DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) + DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) + DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) < DECIMAL_LO64_GET(*pdecL)) {
-      DECIMAL_HI32(decRes)++;
-      if (DECIMAL_HI32(decRes) <= DECIMAL_HI32(*pdecL))
-        goto AlignedScale;
-    }
-    else if (DECIMAL_HI32(decRes) < DECIMAL_HI32(*pdecL)) {
-AlignedScale:
-      // The addition carried above 96 bits.  Divide the result by 10,
-      // dropping the scale factor.
-      // 
-      if (DECIMAL_SCALE(decRes) == 0)
-        FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); // DISP_E_OVERFLOW
-      DECIMAL_SCALE(decRes)--;
-
-      sdlTmp.u.Lo = DECIMAL_HI32(decRes);
-      sdlTmp.u.Hi = 1;
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-      DECIMAL_HI32(decRes) = sdlTmp.u.Lo;
-
-      sdlTmp.u.Lo = DECIMAL_MID32(decRes);
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-      DECIMAL_MID32(decRes) = sdlTmp.u.Lo;
-
-      sdlTmp.u.Lo = DECIMAL_LO32(decRes);
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-      DECIMAL_LO32(decRes) = sdlTmp.u.Lo;
-
-      // See if we need to round up.
-      //
-      if (sdlTmp.u.Hi >= 5 && (sdlTmp.u.Hi > 5 || (DECIMAL_LO32(decRes) & 1))) {
-            DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(decRes)+1);
-            if (DECIMAL_LO64_GET(decRes) == 0)
-          DECIMAL_HI32(decRes)++;
-      }
-    }
-      }
-    }
-    else {
-      // Scale factors are not equal.  Assume that a larger scale
-      // factor (more decimal places) is likely to mean that number
-      // is smaller.  Start by guessing that the right operand has
-      // the larger scale factor.  The result will have the larger
-      // scale factor.
-      //
-      DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecR);  // scale factor of "smaller"
-      DECIMAL_SIGN(decRes) = DECIMAL_SIGN(*pdecL);    // but sign of "larger"
-      iScale = DECIMAL_SCALE(decRes)- DECIMAL_SCALE(*pdecL);
-
-      if (iScale < 0) {
-    // Guessed scale factor wrong. Swap operands.
-    //
-    iScale = -iScale;
-    DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecL);
-    DECIMAL_SIGN(decRes) ^= bSign;
-    pdecTmp = pdecR;
-    pdecR = pdecL;
-    pdecL = pdecTmp;
-      }
-
-      // *pdecL will need to be multiplied by 10^iScale so
-      // it will have the same scale as *pdecR.  We could be
-      // extending it to up to 192 bits of precision.
-      //
-      if (iScale <= POWER10_MAX) {
-    // Scaling won't make it larger than 4 ULONGs
-    //
-    ulPwr = rgulPower10[iScale];
-    DECIMAL_LO64_SET(decTmp, UInt32x32To64(DECIMAL_LO32(*pdecL), ulPwr));
-    sdlTmp.int64 = UInt32x32To64(DECIMAL_MID32(*pdecL), ulPwr);
-    sdlTmp.int64 += DECIMAL_MID32(decTmp);
-    DECIMAL_MID32(decTmp) = sdlTmp.u.Lo;
-    DECIMAL_HI32(decTmp) = sdlTmp.u.Hi;
-    sdlTmp.int64 = UInt32x32To64(DECIMAL_HI32(*pdecL), ulPwr);
-    sdlTmp.int64 += DECIMAL_HI32(decTmp);
-    if (sdlTmp.u.Hi == 0) {
-      // Result fits in 96 bits.  Use standard aligned add.
-      //
-      DECIMAL_HI32(decTmp) = sdlTmp.u.Lo;
-      pdecL = &decTmp;
-      goto AlignedAdd;
-    }
-    rgulNum[0] = DECIMAL_LO32(decTmp);
-    rgulNum[1] = DECIMAL_MID32(decTmp);
-    rgulNum[2] = sdlTmp.u.Lo;
-    rgulNum[3] = sdlTmp.u.Hi;
-    iHiProd = 3;
-      }
-      else {
-    // Have to scale by a bunch.  Move the number to a buffer
-    // where it has room to grow as it's scaled.
-    //
-    rgulNum[0] = DECIMAL_LO32(*pdecL);
-    rgulNum[1] = DECIMAL_MID32(*pdecL);
-    rgulNum[2] = DECIMAL_HI32(*pdecL);
-    iHiProd = 2;
-
-    // Scan for zeros in the upper words.
-    //
-    if (rgulNum[2] == 0) {
-      iHiProd = 1;
-      if (rgulNum[1] == 0) {
-        iHiProd = 0;
-        if (rgulNum[0] == 0) {
-          // Left arg is zero, return right.
-          //
-          DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecR));
-          DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecR);
-          DECIMAL_SIGN(decRes) ^= bSign;
-          goto RetDec;
-        }
-      }
-    }
-
-    // Scaling loop, up to 10^9 at a time.  iHiProd stays updated
-    // with index of highest non-zero ULONG.
-    //
-    for (; iScale > 0; iScale -= POWER10_MAX) {
-      if (iScale > POWER10_MAX)
-        ulPwr = ulTenToNine;
-      else
-        ulPwr = rgulPower10[iScale];
-
-      sdlTmp.u.Hi = 0;
-      for (iCur = 0; iCur <= iHiProd; iCur++) {
-        sdlTmp.int64 = UInt32x32To64(rgulNum[iCur], ulPwr) + sdlTmp.u.Hi;
-        rgulNum[iCur] = sdlTmp.u.Lo;
-      }
-
-      if (sdlTmp.u.Hi != 0)
-        // We're extending the result by another ULONG.
-        rgulNum[++iHiProd] = sdlTmp.u.Hi;
-    }
-      }
-
-      // Scaling complete, do the add.  Could be subtract if signs differ.
-      //
-      sdlTmp.u.Lo = rgulNum[0];
-      sdlTmp.u.Hi = rgulNum[1];
-
-      if (bSign) {
-    // Signs differ, subtract.
-    //
-    DECIMAL_LO64_SET(decRes, (sdlTmp.int64 - DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = rgulNum[2] - DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) > sdlTmp.int64) {
-      DECIMAL_HI32(decRes)--;
-      if (DECIMAL_HI32(decRes) >= rgulNum[2])
-        goto LongSub;
-    }
-    else if (DECIMAL_HI32(decRes) > rgulNum[2]) {
-LongSub:
-      // If rgulNum has more than 96 bits of precision, then we need to 
-      // carry the subtraction into the higher bits.  If it doesn't, 
-      // then we subtracted in the wrong order and have to flip the 
-      // sign of the result.
-      // 
-      if (iHiProd <= 2)
-        goto SignFlip;
-
-      iCur = 3;
-      while(rgulNum[iCur++]-- == 0);
-      if (rgulNum[iHiProd] == 0)
-        iHiProd--;
-    }
-      }
-      else {
-    // Signs the same, add.
-    //
-    DECIMAL_LO64_SET(decRes, (sdlTmp.int64 + DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = rgulNum[2] + DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) < sdlTmp.int64) {
-      DECIMAL_HI32(decRes)++;
-      if (DECIMAL_HI32(decRes) <= rgulNum[2])
-        goto LongAdd;
-    }
-    else if (DECIMAL_HI32(decRes) < rgulNum[2]) {
-LongAdd:
-      // Had a carry above 96 bits.
-      //
-      iCur = 3;
-      do {
-        if (iHiProd < iCur) {
-          rgulNum[iCur] = 1;
-          iHiProd = iCur;
-          break;
-        }
-      }while (++rgulNum[iCur++] == 0);
-    }
-      }
-
-      if (iHiProd > 2) {
-    rgulNum[0] = DECIMAL_LO32(decRes);
-    rgulNum[1] = DECIMAL_MID32(decRes);
-    rgulNum[2] = DECIMAL_HI32(decRes);
-    DECIMAL_SCALE(decRes) = (BYTE)ScaleResult(rgulNum, iHiProd, DECIMAL_SCALE(decRes));
-    if (DECIMAL_SCALE(decRes) == (BYTE)-1)
-      FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); // DISP_E_OVERFLOW
-
-    DECIMAL_LO32(decRes) = rgulNum[0];
-    DECIMAL_MID32(decRes) = rgulNum[1];
-    DECIMAL_HI32(decRes) = rgulNum[2];
-      }
-    }
-
-RetDec:
-    pdecL = pdecLOriginal;
-    COPYDEC(*pdecL, decRes)
-    pdecL->wReserved = 0;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
-FCIMPL4(void, COMDecimal::DoAddSub, DECIMAL * pdecL, DECIMAL * pdecR, UINT8 bSign, CLR_BOOL * overflowed)
-{
-    FCALL_CONTRACT;
-
-    ULONG     rgulNum[6];
-    ULONG     ulPwr;
-    int       iScale;
-    int       iHiProd;
-    int       iCur;
-    SPLIT64   sdlTmp;
-    DECIMAL   decRes;
-    DECIMAL   decTmp;
-    LPDECIMAL pdecTmp;
-    LPDECIMAL pdecLOriginal;
-
-    _ASSERTE(bSign == 0 || bSign == DECIMAL_NEG);
-
-    pdecLOriginal = pdecL;
-
-    bSign ^= (DECIMAL_SIGN(*pdecR) ^ DECIMAL_SIGN(*pdecL)) & DECIMAL_NEG;
-
-    if (DECIMAL_SCALE(*pdecR) == DECIMAL_SCALE(*pdecL)) {
-      // Scale factors are equal, no alignment necessary.
-      //
-      DECIMAL_SIGNSCALE(decRes) = DECIMAL_SIGNSCALE(*pdecL);
-
-AlignedAdd:
-      if (bSign) {
-    // Signs differ - subtract
-    //
-    DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) - DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) - DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) > DECIMAL_LO64_GET(*pdecL)) {
-      DECIMAL_HI32(decRes)--;
-      if (DECIMAL_HI32(decRes) >= DECIMAL_HI32(*pdecL))
-        goto SignFlip;
-    }
-    else if (DECIMAL_HI32(decRes) > DECIMAL_HI32(*pdecL)) {
-      // Got negative result.  Flip its sign.
-      // 
-SignFlip:
-      DECIMAL_LO64_SET(decRes, -(LONGLONG)DECIMAL_LO64_GET(decRes));
-      DECIMAL_HI32(decRes) = ~DECIMAL_HI32(decRes);
-      if (DECIMAL_LO64_GET(decRes) == 0)
-        DECIMAL_HI32(decRes)++;
-      DECIMAL_SIGN(decRes) ^= DECIMAL_NEG;
-    }
-
-      }
-      else {
-    // Signs are the same - add
-    //
-    DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) + DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) + DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) < DECIMAL_LO64_GET(*pdecL)) {
-      DECIMAL_HI32(decRes)++;
-      if (DECIMAL_HI32(decRes) <= DECIMAL_HI32(*pdecL))
-        goto AlignedScale;
-    }
-    else if (DECIMAL_HI32(decRes) < DECIMAL_HI32(*pdecL)) {
-AlignedScale:
-      // The addition carried above 96 bits.  Divide the result by 10,
-      // dropping the scale factor.
-      // 
-      if (DECIMAL_SCALE(decRes) == 0) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-      }
-      DECIMAL_SCALE(decRes)--;
-
-      sdlTmp.u.Lo = DECIMAL_HI32(decRes);
-      sdlTmp.u.Hi = 1;
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-      DECIMAL_HI32(decRes) = sdlTmp.u.Lo;
-
-      sdlTmp.u.Lo = DECIMAL_MID32(decRes);
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-      DECIMAL_MID32(decRes) = sdlTmp.u.Lo;
-
-      sdlTmp.u.Lo = DECIMAL_LO32(decRes);
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-      DECIMAL_LO32(decRes) = sdlTmp.u.Lo;
-
-      // See if we need to round up.
-      //
-      if (sdlTmp.u.Hi >= 5 && (sdlTmp.u.Hi > 5 || (DECIMAL_LO32(decRes) & 1))) {
-            DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(decRes)+1);
-            if (DECIMAL_LO64_GET(decRes) == 0)
-          DECIMAL_HI32(decRes)++;
-      }
-    }
-      }
-    }
-    else {
-      // Scale factors are not equal.  Assume that a larger scale
-      // factor (more decimal places) is likely to mean that number
-      // is smaller.  Start by guessing that the right operand has
-      // the larger scale factor.  The result will have the larger
-      // scale factor.
-      //
-      DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecR);  // scale factor of "smaller"
-      DECIMAL_SIGN(decRes) = DECIMAL_SIGN(*pdecL);    // but sign of "larger"
-      iScale = DECIMAL_SCALE(decRes)- DECIMAL_SCALE(*pdecL);
-
-      if (iScale < 0) {
-    // Guessed scale factor wrong. Swap operands.
-    //
-    iScale = -iScale;
-    DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecL);
-    DECIMAL_SIGN(decRes) ^= bSign;
-    pdecTmp = pdecR;
-    pdecR = pdecL;
-    pdecL = pdecTmp;
-      }
-
-      // *pdecL will need to be multiplied by 10^iScale so
-      // it will have the same scale as *pdecR.  We could be
-      // extending it to up to 192 bits of precision.
-      //
-      if (iScale <= POWER10_MAX) {
-    // Scaling won't make it larger than 4 ULONGs
-    //
-    ulPwr = rgulPower10[iScale];
-    DECIMAL_LO64_SET(decTmp, UInt32x32To64(DECIMAL_LO32(*pdecL), ulPwr));
-    sdlTmp.int64 = UInt32x32To64(DECIMAL_MID32(*pdecL), ulPwr);
-    sdlTmp.int64 += DECIMAL_MID32(decTmp);
-    DECIMAL_MID32(decTmp) = sdlTmp.u.Lo;
-    DECIMAL_HI32(decTmp) = sdlTmp.u.Hi;
-    sdlTmp.int64 = UInt32x32To64(DECIMAL_HI32(*pdecL), ulPwr);
-    sdlTmp.int64 += DECIMAL_HI32(decTmp);
-    if (sdlTmp.u.Hi == 0) {
-      // Result fits in 96 bits.  Use standard aligned add.
-      //
-      DECIMAL_HI32(decTmp) = sdlTmp.u.Lo;
-      pdecL = &decTmp;
-      goto AlignedAdd;
-    }
-    rgulNum[0] = DECIMAL_LO32(decTmp);
-    rgulNum[1] = DECIMAL_MID32(decTmp);
-    rgulNum[2] = sdlTmp.u.Lo;
-    rgulNum[3] = sdlTmp.u.Hi;
-    iHiProd = 3;
-      }
-      else {
-    // Have to scale by a bunch.  Move the number to a buffer
-    // where it has room to grow as it's scaled.
-    //
-    rgulNum[0] = DECIMAL_LO32(*pdecL);
-    rgulNum[1] = DECIMAL_MID32(*pdecL);
-    rgulNum[2] = DECIMAL_HI32(*pdecL);
-    iHiProd = 2;
-
-    // Scan for zeros in the upper words.
-    //
-    if (rgulNum[2] == 0) {
-      iHiProd = 1;
-      if (rgulNum[1] == 0) {
-        iHiProd = 0;
-        if (rgulNum[0] == 0) {
-          // Left arg is zero, return right.
-          //
-          DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecR));
-          DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecR);
-          DECIMAL_SIGN(decRes) ^= bSign;
-          goto RetDec;
-        }
-      }
-    }
-
-    // Scaling loop, up to 10^9 at a time.  iHiProd stays updated
-    // with index of highest non-zero ULONG.
-    //
-    for (; iScale > 0; iScale -= POWER10_MAX) {
-      if (iScale > POWER10_MAX)
-        ulPwr = ulTenToNine;
-      else
-        ulPwr = rgulPower10[iScale];
-
-      sdlTmp.u.Hi = 0;
-      for (iCur = 0; iCur <= iHiProd; iCur++) {
-        sdlTmp.int64 = UInt32x32To64(rgulNum[iCur], ulPwr) + sdlTmp.u.Hi;
-        rgulNum[iCur] = sdlTmp.u.Lo;
-      }
-
-      if (sdlTmp.u.Hi != 0)
-        // We're extending the result by another ULONG.
-        rgulNum[++iHiProd] = sdlTmp.u.Hi;
-    }
-      }
-
-      // Scaling complete, do the add.  Could be subtract if signs differ.
-      //
-      sdlTmp.u.Lo = rgulNum[0];
-      sdlTmp.u.Hi = rgulNum[1];
-
-      if (bSign) {
-    // Signs differ, subtract.
-    //
-    DECIMAL_LO64_SET(decRes, (sdlTmp.int64 - DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = rgulNum[2] - DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) > sdlTmp.int64) {
-      DECIMAL_HI32(decRes)--;
-      if (DECIMAL_HI32(decRes) >= rgulNum[2])
-        goto LongSub;
-    }
-    else if (DECIMAL_HI32(decRes) > rgulNum[2]) {
-LongSub:
-      // If rgulNum has more than 96 bits of precision, then we need to 
-      // carry the subtraction into the higher bits.  If it doesn't, 
-      // then we subtracted in the wrong order and have to flip the 
-      // sign of the result.
-      // 
-      if (iHiProd <= 2)
-        goto SignFlip;
-
-      iCur = 3;
-      while(rgulNum[iCur++]-- == 0);
-      if (rgulNum[iHiProd] == 0)
-        iHiProd--;
-    }
-      }
-      else {
-    // Signs the same, add.
-    //
-    DECIMAL_LO64_SET(decRes, (sdlTmp.int64 + DECIMAL_LO64_GET(*pdecR)));
-    DECIMAL_HI32(decRes) = rgulNum[2] + DECIMAL_HI32(*pdecR);
-
-    // Propagate carry
-    //
-    if (DECIMAL_LO64_GET(decRes) < sdlTmp.int64) {
-      DECIMAL_HI32(decRes)++;
-      if (DECIMAL_HI32(decRes) <= rgulNum[2])
-        goto LongAdd;
-    }
-    else if (DECIMAL_HI32(decRes) < rgulNum[2]) {
-LongAdd:
-      // Had a carry above 96 bits.
-      //
-      iCur = 3;
-      do {
-        if (iHiProd < iCur) {
-          rgulNum[iCur] = 1;
-          iHiProd = iCur;
-          break;
-        }
-      }while (++rgulNum[iCur++] == 0);
-    }
-      }
-
-      if (iHiProd > 2) {
-    rgulNum[0] = DECIMAL_LO32(decRes);
-    rgulNum[1] = DECIMAL_MID32(decRes);
-    rgulNum[2] = DECIMAL_HI32(decRes);
-    DECIMAL_SCALE(decRes) = (BYTE)ScaleResult(rgulNum, iHiProd, DECIMAL_SCALE(decRes));
-    if (DECIMAL_SCALE(decRes) == (BYTE)-1) {
-          *overflowed = true;
-          FC_GC_POLL();
-          return;
-    }
-
-    DECIMAL_LO32(decRes) = rgulNum[0];
-    DECIMAL_MID32(decRes) = rgulNum[1];
-    DECIMAL_HI32(decRes) = rgulNum[2];
-      }
-    }
-
-RetDec:
-    pdecL = pdecLOriginal;
-    COPYDEC(*pdecL, decRes)
-    pdecL->wReserved = 0;
-    FC_GC_POLL();
-}
-FCIMPLEND
-
diff --git a/src/coreclr/src/classlibnative/bcltype/decimal.h b/src/coreclr/src/classlibnative/bcltype/decimal.h
deleted file mode 100644 (file)
index f037fd3..0000000
+++ /dev/null
@@ -1,52 +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: Decimal.h
-//
-
-//
-
-#ifndef _DECIMAL_H_
-#define _DECIMAL_H_
-
-#include <oleauto.h>
-
-#include <pshpack1.h>
-
-#include "number.h"
-
-#define DECIMAL_PRECISION 29
-
-class COMDecimal {
-public:
-    static FCDECL2_IV(void, InitSingle, DECIMAL *_this, float value);
-    static FCDECL2_IV(void, InitDouble, DECIMAL *_this, double value);
-    static FCDECL2(INT32, DoCompare, DECIMAL * d1, DECIMAL * d2);
-
-    static FCDECL3(void, DoAddSubThrow, DECIMAL * d1, DECIMAL * d2, UINT8 bSign);
-    static FCDECL2(void, DoDivideThrow, DECIMAL * d1, DECIMAL * d2);
-    static FCDECL2(void, DoMultiplyThrow, DECIMAL * d1, DECIMAL * d2);
-
-    static FCDECL4(void, DoAddSub, DECIMAL * d1, DECIMAL * d2, UINT8 bSign, CLR_BOOL * overflowed);
-    static FCDECL3(void, DoDivide, DECIMAL * d1, DECIMAL * d2, CLR_BOOL * overflowed);
-    static FCDECL3(void, DoMultiply, DECIMAL * d1, DECIMAL * d2, CLR_BOOL * overflowed);
-
-    static FCDECL2(void, DoRound, DECIMAL * d1, INT32 decimals);
-    static FCDECL2_IV(void, DoToCurrency, CY * result, DECIMAL d);
-    static FCDECL1(void, DoTruncate, DECIMAL * d);
-    static FCDECL1(void, DoFloor, DECIMAL * d);
-
-    static FCDECL1(double, ToDouble, FC_DECIMAL d);
-    static FCDECL1(float, ToSingle, FC_DECIMAL d);
-    static FCDECL1(INT32, ToInt32, FC_DECIMAL d);      
-    static FCDECL1(Object*, ToString, FC_DECIMAL d);
-    
-    static int NumberToDecimal(NUMBER* number, DECIMAL* value);
-    
-
-};
-
-#include <poppack.h>
-
-#endif // _DECIMAL_H_
index ac068d6..b4bf7a5 100644 (file)
@@ -11,7 +11,6 @@
 #include "excep.h"
 #include "number.h"
 #include "string.h"
-#include "decimal.h"
 #include "bignum.h"
 #include "grisu3.h"
 #include "fp.h"
@@ -1278,6 +1277,7 @@ STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF
     */
 
     _ASSERTE(numfmt != NULL);
+    _ASSERTE(!bDecimal);
     UINT64 newBufferLen = MIN_BUFFER_SIZE;
 
     CQuickBytesSpecifySize<LARGE_BUFFER_SIZE * sizeof(WCHAR)> buf;
@@ -1441,15 +1441,8 @@ STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF
         {
             bool enableRounding = true;
             if (nMaxDigits < 1) {
-                if (bDecimal && (nMaxDigits == -1)) { // Default to 29 digits precision only for G formatting without a precision specifier
-                    // This ensures that the PAL code pads out to the correct place even when we use the default precision
-                    nMaxDigits = nMinDigits = DECIMAL_PRECISION;
-                    enableRounding = false;  // Turn off rounding for ECMA compliance to output trailing 0's after decimal as significant
-                }
-                else {
-                    // This ensures that the PAL code pads out to the correct place even when we use the default precision
-                    nMaxDigits = nMinDigits = number->precision;
-                }
+                // This ensures that the PAL code pads out to the correct place even when we use the default precision
+                nMaxDigits = nMinDigits = number->precision;
             }
             else
                 nMinDigits=nMaxDigits;
@@ -1471,11 +1464,6 @@ STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF
 
             if (enableRounding) // Don't round for G formatting without precision
                 RoundNumber(number, nMaxDigits); // This also fixes up the minus zero case
-            else {
-                if (bDecimal && ((GetDigitsBuffer(number))[0] == 0)) { // Minus zero should be formatted as 0
-                    number->sign = 0;
-                }
-            }
             if (number->sign) {
                 AddStringRef(&dst, sNegative);
             }
@@ -2000,11 +1988,3 @@ FCIMPL1(double, COMNumber::NumberToDoubleFC, NUMBER* number)
     return d;
 }
 FCIMPLEND
-
-FCIMPL2(FC_BOOL_RET, COMNumber::NumberBufferToDecimal, NUMBER* number, DECIMAL* value)
-{
-    FCALL_CONTRACT;
-
-    FC_RETURN_BOOL(COMDecimal::NumberToDecimal(number, value) != 0);
-}
-FCIMPLEND
index bf1f328..0fd12b1 100644 (file)
@@ -33,7 +33,6 @@ class COMNumber
 public:
     static FCDECL3_VII(void, DoubleToNumberFC, double value, int precision, NUMBER* number);
     static FCDECL1(double, NumberToDoubleFC, NUMBER* number);
-    static FCDECL2(FC_BOOL_RET, NumberBufferToDecimal, NUMBER* number, DECIMAL* value);
     
     static wchar_t* Int32ToDecChars(__in wchar_t* p, unsigned int value, int digits);
 };
index 2d7f1c1..15d18f5 100644 (file)
@@ -1057,55 +1057,36 @@ inline int CountBits(int iNum)
 
 #include "bitposition.h"
 
-// Used to remove trailing zeros from Decimal types.
-// NOTE: Assumes hi32 bits are empty (used for conversions from Cy->Dec)
-inline HRESULT DecimalCanonicalize(DECIMAL* dec)
+// Convert the currency to a decimal and canonicalize.
+inline void VarDecFromCyCanonicalize(CY cyIn, DECIMAL* dec)
 {
     WRAPPER_NO_CONTRACT;
 
-    // Clear the VARENUM field
-    (*(USHORT*)dec) = 0;
-
-    // Remove trailing zeros:
-    DECIMAL temp;
-    DECIMAL templast;
-    temp = templast = *dec;
-
-    // Ensure the hi 32 bits are empty (should be if we came from a currency)
-    if ((DECIMAL_HI32(temp) != 0) || (DECIMAL_SCALE(temp) > 4))
-        return DISP_E_OVERFLOW;
-
-    // Return immediately if dec represents a zero.
-    if (DECIMAL_LO32(temp) == 0 && DECIMAL_MID32(temp) == 0)
-        return S_OK;
-
-    // Compare to the original to see if we've
-    // lost non-zero digits (and make sure we don't overflow the scale BYTE)
-
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:6219) // "Suppress PREFast warning about Implicit cast between semantically different integer types" 
-#endif
-    while ((DECIMAL_SCALE(temp) <= 4) && (VARCMP_EQ == VarDecCmp(dec, &temp)))
+    (*(ULONG*)dec) = 0;
+    DECIMAL_HI32(*dec) = 0;
+    if (cyIn.int64 == 0) // For compatibility, a currency of 0 emits the Decimal "0.0000" (scale set to 4).
     {
+        DECIMAL_SCALE(*dec) = 4;
+        DECIMAL_LO32(*dec) = 0;
+        DECIMAL_MID32(*dec) = 0;
+        return;
+    }
 
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-        templast = temp;
-
-        // Remove the last digit and normalize.  Ignore temp.Hi32
-        // as Currency values will have a max of 64 bits of data.
-        DECIMAL_SCALE(temp)--;
-        UINT64 temp64 = (((UINT64) DECIMAL_MID32(temp)) << 32) + DECIMAL_LO32(temp);
-        temp64 /= 10;
-
-        DECIMAL_MID32(temp) = (ULONG)(temp64 >> 32);
-        DECIMAL_LO32(temp) = (ULONG)temp64;
+    if (cyIn.int64 < 0) {
+        DECIMAL_SIGN(*dec) = DECIMAL_NEG;
+        cyIn.int64 = -cyIn.int64;
     }
-    *dec = templast;
 
-    return S_OK;
+    BYTE scale = 4;
+    ULONGLONG absoluteCy = (ULONGLONG)cyIn.int64;
+    while (scale != 0 && ((absoluteCy % 10) == 0))
+    {
+        scale--;
+        absoluteCy /= 10;
+    }
+    DECIMAL_SCALE(*dec) = scale;
+    DECIMAL_LO32(*dec) = (ULONG)absoluteCy;
+    DECIMAL_MID32(*dec) = (ULONG)(absoluteCy >> 32);
 }
 
 //*****************************************************************************
index e19b55d..e5ca200 100644 (file)
@@ -5,8 +5,6 @@ set(PALRT_SOURCES
     bstr.cpp
     coguid.cpp
     comem.cpp
-    decarith.cpp
-    decconv.cpp
     guid.cpp
     memorystream.cpp
     path.cpp
diff --git a/src/coreclr/src/palrt/decarith.cpp b/src/coreclr/src/palrt/decarith.cpp
deleted file mode 100644 (file)
index f190707..0000000
+++ /dev/null
@@ -1,1267 +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: decarith.cpp
-// 
-// ===========================================================================
-/***
-*
-*Purpose:
-*  Implement arithmetic for Decimal data type.
-*
-*Implementation Notes:
-*
-*****************************************************************************/
-
-#include "common.h"
-
-#include <oleauto.h>
-#include "convert.h"
-
-//***********************************************************************
-//
-// Additional Decimal and Int64 definitions
-//
-#define COPYDEC(dest, src) {DECIMAL_SIGNSCALE(dest) = DECIMAL_SIGNSCALE(src); DECIMAL_HI32(dest) = DECIMAL_HI32(src); \
-    DECIMAL_MID32(dest) = DECIMAL_MID32(src); DECIMAL_LO32(dest) = DECIMAL_LO32(src); }
-
-#define DEC_SCALE_MAX   28
-#define POWER10_MAX     9
-
-// The following functions are defined in the classlibnative\bcltype\decimal.cpp
-ULONG Div96By32(ULONG *rgulNum, ULONG ulDen);
-ULONG Div96By64(ULONG *rgulNum, SPLIT64 sdlDen);
-ULONG Div128By96(ULONG *rgulNum, ULONG *rgulDen);
-int ScaleResult(ULONG *rgulRes, int iHiRes, int iScale);
-ULONG IncreaseScale(ULONG *rgulNum, ULONG ulPwr);
-
-//***********************************************************************
-//
-// Data tables
-//
-
-static ULONG rgulPower10[POWER10_MAX+1] = {1, 10, 100, 1000, 10000, 100000, 1000000,
-                                           10000000, 100000000, 1000000000};
-
-struct DECOVFL
-{
-    ULONG Hi;
-    ULONG Mid;
-};
-
-static DECOVFL PowerOvfl[] = {
-// This is a table of the largest values that can be in the upper two
-// ULONGs of a 96-bit number that will not overflow when multiplied
-// by a given power.  For the upper word, this is a table of 
-// 2^32 / 10^n for 1 <= n <= 9.  For the lower word, this is the
-// remaining fraction part * 2^32.  2^32 = 4294967296.
-//
-    { 429496729UL, 2576980377UL }, // 10^1 remainder 0.6
-    { 42949672UL,  4123168604UL }, // 10^2 remainder 0.16
-    { 4294967UL,   1271310319UL }, // 10^3 remainder 0.616
-    { 429496UL,    3133608139UL }, // 10^4 remainder 0.1616
-    { 42949UL,     2890341191UL }, // 10^5 remainder 0.51616
-    { 4294UL,      4154504685UL }, // 10^6 remainder 0.551616
-    { 429UL,       2133437386UL }, // 10^7 remainder 0.9551616
-    { 42UL,        4078814305UL }, // 10^8 remainder 0.09991616
-//  { 4UL,         1266874889UL }, // 10^9 remainder 0.709551616
-};
-
-#define OVFL_MAX_9_HI   4
-#define OVFL_MAX_9_MID  1266874889
-
-#define OVFL_MAX_5_HI   42949
-#define OVFL_MAX_5_MID  2890341191
-
-#define OVFL_MAX_1_HI   429496729
-
-
-
-//***********************************************************************
-//
-// static helper functions
-//
-
-/***
-* FullDiv64By32
-*
-* Entry:
-*   pdlNum  - Pointer to 64-bit dividend
-*   ulDen   - 32-bit divisor
-*
-* Purpose:
-*   Do full divide, yielding 64-bit result and 32-bit remainder.
-*
-* Exit:
-*   Quotient overwrites dividend.
-*   Returns remainder.
-*
-* Exceptions:
-*   None.
-*
-***********************************************************************/
-
-ULONG FullDiv64By32(DWORDLONG *pdlNum, ULONG ulDen)
-{
-    SPLIT64  sdlTmp;
-    SPLIT64  sdlRes;
-
-    sdlTmp.int64 = *pdlNum;
-    sdlRes.u.Hi = 0;
-
-    if (sdlTmp.u.Hi >= ulDen) {
-      // DivMod64by32 returns quotient in Lo, remainder in Hi.
-      //
-      sdlRes.u.Lo = sdlTmp.u.Hi;
-      sdlRes.int64 = DivMod64by32(sdlRes.int64, ulDen);
-      sdlTmp.u.Hi = sdlRes.u.Hi;
-      sdlRes.u.Hi = sdlRes.u.Lo;
-    }
-
-    sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen);
-    sdlRes.u.Lo = sdlTmp.u.Lo;
-    *pdlNum = sdlRes.int64;
-    return sdlTmp.u.Hi;
-}
-
-
-
-
-/***
-* SearchScale
-*
-* Entry:
-*   ulResHi - Top ULONG of quotient
-*   ulResLo - Middle ULONG of quotient
-*   iScale  - Scale factor of quotient, range -DEC_SCALE_MAX to DEC_SCALE_MAX
-*
-* Purpose:
-*   Determine the max power of 10, <= 9, that the quotient can be scaled
-*   up by and still fit in 96 bits.
-*
-* Exit:
-*   Returns power of 10 to scale by, -1 if overflow error.
-*
-***********************************************************************/
-
-int SearchScale(ULONG ulResHi, ULONG ulResLo, int iScale)
-{
-    int   iCurScale;
-
-    // Quick check to stop us from trying to scale any more.
-    //
-    if (ulResHi > OVFL_MAX_1_HI || iScale >= DEC_SCALE_MAX) {
-      iCurScale = 0;
-      goto HaveScale;
-    }
-
-    if (iScale > DEC_SCALE_MAX - 9) {
-      // We can't scale by 10^9 without exceeding the max scale factor.
-      // See if we can scale to the max.  If not, we'll fall into
-      // standard search for scale factor.
-      //
-      iCurScale = DEC_SCALE_MAX - iScale;
-      if (ulResHi < PowerOvfl[iCurScale - 1].Hi)
-        goto HaveScale;
-
-      if (ulResHi == PowerOvfl[iCurScale - 1].Hi) {
-  UpperEq:
-        if (ulResLo >= PowerOvfl[iCurScale - 1].Mid)
-          iCurScale--;
-        goto HaveScale;
-      }
-    }
-    else if (ulResHi < OVFL_MAX_9_HI || (ulResHi == OVFL_MAX_9_HI && 
-          ulResLo < OVFL_MAX_9_MID))
-      return 9;
-
-    // Search for a power to scale by < 9.  Do a binary search
-    // on PowerOvfl[].
-    //
-    iCurScale = 5;
-    if (ulResHi < OVFL_MAX_5_HI)
-      iCurScale = 7;
-    else if (ulResHi > OVFL_MAX_5_HI)
-      iCurScale = 3;
-    else
-      goto UpperEq;
-
-    // iCurScale is 3 or 7.
-    //
-    if (ulResHi < PowerOvfl[iCurScale - 1].Hi)
-      iCurScale++;
-    else if (ulResHi > PowerOvfl[iCurScale - 1].Hi)
-      iCurScale--;
-    else
-      goto UpperEq;
-
-    // iCurScale is 2, 4, 6, or 8.
-    //
-    // In all cases, we already found we could not use the power one larger.
-    // So if we can use this power, it is the biggest, and we're done.  If
-    // we can't use this power, the one below it is correct for all cases 
-    // unless it's 10^1 -- we might have to go to 10^0 (no scaling).
-    // 
-    if (ulResHi > PowerOvfl[iCurScale - 1].Hi)
-      iCurScale--;
-
-    if (ulResHi == PowerOvfl[iCurScale - 1].Hi)
-      goto UpperEq;
-
-HaveScale:
-    // iCurScale = largest power of 10 we can scale by without overflow, 
-    // iCurScale < 9.  See if this is enough to make scale factor 
-    // positive if it isn't already.
-    // 
-    if (iCurScale + iScale < 0)
-      iCurScale = -1;
-
-    return iCurScale;
-}
-
-/***
-* DecFixInt
-*
-* Entry:
-*   pdecRes - Pointer to Decimal result location
-*   pdecIn  - Pointer to Decimal operand
-*
-* Purpose:
-*   Chop the value to integer.  Return remainder so Int() function
-*   can round down if non-zero.
-*
-* Exit:
-*   Returns remainder.
-*
-* Exceptions:
-*   None.
-*
-***********************************************************************/
-
-ULONG DecFixInt(LPDECIMAL pdecRes, LPDECIMAL pdecIn)
-{
-    ULONG   rgulNum[3];
-    ULONG   ulRem;
-    ULONG   ulPwr;
-    int     iScale;
-
-    if (pdecIn->u.u.scale > 0) {
-      rgulNum[0] = pdecIn->v.v.Lo32;
-      rgulNum[1] = pdecIn->v.v.Mid32;
-      rgulNum[2] = pdecIn->Hi32;
-      iScale = pdecIn->u.u.scale;
-      pdecRes->u.u.sign = pdecIn->u.u.sign;
-      ulRem = 0;
-
-      do {
-        if (iScale > POWER10_MAX)
-          ulPwr = ulTenToNine;
-        else
-          ulPwr = rgulPower10[iScale];
-
-        ulRem |= Div96By32(rgulNum, ulPwr);
-        iScale -= 9;
-      }while (iScale > 0);
-
-      pdecRes->v.v.Lo32 = rgulNum[0];
-      pdecRes->v.v.Mid32 = rgulNum[1];
-      pdecRes->Hi32 = rgulNum[2];
-      pdecRes->u.u.scale = 0;
-
-      return ulRem;
-    }
-
-    COPYDEC(*pdecRes, *pdecIn)
-    return 0;
-}
-
-
-//***********************************************************************
-//
-// 
-//
-
-//**********************************************************************
-//
-// VarDecMul - Decimal Multiply
-//
-//**********************************************************************
-
-STDAPI VarDecMul(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
-    SPLIT64 sdlTmp;
-    SPLIT64 sdlTmp2;
-    SPLIT64 sdlTmp3;
-    int     iScale;
-    int     iHiProd;
-    ULONG   ulPwr;
-    ULONG   ulRemLo;
-    ULONG   ulRemHi;
-    ULONG   rgulProd[6];
-
-    iScale = pdecL->u.u.scale + pdecR->u.u.scale;
-
-    if ((pdecL->Hi32 | pdecL->v.v.Mid32 | pdecR->Hi32 | pdecR->v.v.Mid32) == 0)
-    {
-      // Upper 64 bits are zero.
-      //
-      sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->v.v.Lo32);
-      if (iScale > DEC_SCALE_MAX)
-      {
-              // Result iScale is too big.  Divide result by power of 10 to reduce it.
-              // If the amount to divide by is > 19 the result is guaranteed
-              // less than 1/2.  [max value in 64 bits = 1.84E19]
-              //
-              iScale -= DEC_SCALE_MAX;
-              if (iScale > 19)
-        {
-ReturnZero:
-                DECIMAL_SETZERO(*pdecRes);
-                return NOERROR;
-              }
-              if (iScale > POWER10_MAX) 
-        {
-                // Divide by 1E10 first, to get the power down to a 32-bit quantity.
-                // 1E10 itself doesn't fit in 32 bits, so we'll divide by 2.5E9 now
-                // then multiply the next divisor by 4 (which will be a max of 4E9).
-                // 
-                ulRemLo = FullDiv64By32(&sdlTmp.int64, ulTenToTenDiv4);
-                ulPwr = rgulPower10[iScale - 10] << 2;
-              }
-              else 
-        {
-                ulPwr = rgulPower10[iScale];
-                ulRemLo = 0;
-              }
-
-              // Power to divide by fits in 32 bits.
-              //
-              ulRemHi = FullDiv64By32(&sdlTmp.int64, ulPwr);
-
-              // Round result.  See if remainder >= 1/2 of divisor.
-              // Divisor is a power of 10, so it is always even.
-              //
-              ulPwr >>= 1;
-              if (ulRemHi >= ulPwr && (ulRemHi > ulPwr || (ulRemLo | (sdlTmp.u.Lo & 1))))
-                sdlTmp.int64++;
-
-        iScale = DEC_SCALE_MAX;
-      }
-      DECIMAL_LO32(*pdecRes) = sdlTmp.u.Lo;
-      DECIMAL_MID32(*pdecRes) = sdlTmp.u.Hi;
-      DECIMAL_HI32(*pdecRes) = 0;
-    }
-    else 
-    {
-
-      // At least one operand has bits set in the upper 64 bits.
-      //
-      // Compute and accumulate the 9 partial products into a 
-      // 192-bit (24-byte) result.
-      //
-      //                [l-h][l-m][l-l]   left high, middle, low
-      //             x  [r-h][r-m][r-l]   right high, middle, low
-      // ------------------------------
-      //
-      //                     [0-h][0-l]   l-l * r-l
-      //                [1ah][1al]        l-l * r-m
-      //                [1bh][1bl]        l-m * r-l
-      //           [2ah][2al]             l-m * r-m
-      //           [2bh][2bl]             l-l * r-h
-      //           [2ch][2cl]             l-h * r-l
-      //      [3ah][3al]                  l-m * r-h
-      //      [3bh][3bl]                  l-h * r-m
-      // [4-h][4-l]                       l-h * r-h
-      // ------------------------------
-      // [p-5][p-4][p-3][p-2][p-1][p-0]   prod[] array
-      //
-      sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->v.v.Lo32);
-      rgulProd[0] = sdlTmp.u.Lo;
-
-      sdlTmp2.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->v.v.Mid32) + sdlTmp.u.Hi;
-
-      sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, pdecR->v.v.Lo32);
-      sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
-      rgulProd[1] = sdlTmp.u.Lo;
-      if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
-        sdlTmp2.u.Hi = 1;
-      else
-        sdlTmp2.u.Hi = 0;
-      sdlTmp2.u.Lo = sdlTmp.u.Hi;
-
-      sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, pdecR->v.v.Mid32) + sdlTmp2.int64;
-
-      if (pdecL->Hi32 | pdecR->Hi32) {
-        // Highest 32 bits is non-zero.  Calculate 5 more partial products.
-        //
-        sdlTmp2.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->Hi32);
-        sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
-        if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
-          sdlTmp3.u.Hi = 1;
-        else
-          sdlTmp3.u.Hi = 0;
-
-        sdlTmp2.int64 = UInt32x32To64(pdecL->Hi32, pdecR->v.v.Lo32);
-        sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
-        rgulProd[2] = sdlTmp.u.Lo;
-        if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
-          sdlTmp3.u.Hi++;
-        sdlTmp3.u.Lo = sdlTmp.u.Hi;
-
-        sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, pdecR->Hi32);
-        sdlTmp.int64 += sdlTmp3.int64; // this could generate carry
-        if (sdlTmp.int64 < sdlTmp3.int64) // detect carry
-          sdlTmp3.u.Hi = 1;
-        else
-          sdlTmp3.u.Hi = 0;
-
-        sdlTmp2.int64 = UInt32x32To64(pdecL->Hi32, pdecR->v.v.Mid32);
-        sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
-        rgulProd[3] = sdlTmp.u.Lo;
-        if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
-          sdlTmp3.u.Hi++;
-        sdlTmp3.u.Lo = sdlTmp.u.Hi;
-
-        sdlTmp.int64 = UInt32x32To64(pdecL->Hi32, pdecR->Hi32) + sdlTmp3.int64;
-        rgulProd[4] = sdlTmp.u.Lo;
-        rgulProd[5] = sdlTmp.u.Hi;
-
-        iHiProd = 5;
-      }
-      else {
-        rgulProd[2] = sdlTmp.u.Lo;
-        rgulProd[3] = sdlTmp.u.Hi;
-        iHiProd = 3;
-      }
-
-      // Check for leading zero ULONGs on the product
-      //
-      while (rgulProd[iHiProd] == 0) {
-        iHiProd--;
-        if (iHiProd < 0)
-          goto ReturnZero;
-      }
-
-      iScale = ScaleResult(rgulProd, iHiProd, iScale);
-      if (iScale == -1)
-        return DISP_E_OVERFLOW;
-
-      pdecRes->v.v.Lo32 = rgulProd[0];
-      pdecRes->v.v.Mid32 = rgulProd[1];
-      pdecRes->Hi32 = rgulProd[2];
-    }
-
-    pdecRes->u.u.sign = pdecR->u.u.sign ^ pdecL->u.u.sign;
-    pdecRes->u.u.scale = (char)iScale;
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecAdd - Decimal Addition
-// VarDecSub - Decimal Subtraction
-//
-//**********************************************************************
-
-static HRESULT DecAddSub(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes, char bSign);
-
-STDAPI VarDecAdd(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
-    return DecAddSub(pdecL, pdecR, pdecRes, 0);
-}
-
-
-STDAPI VarDecSub(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
-    return DecAddSub(pdecL, pdecR, pdecRes, DECIMAL_NEG);
-}
-
-
-static HRESULT DecAddSub(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes, char bSign)
-{
-    ULONG     rgulNum[6];
-    ULONG     ulPwr;
-    int       iScale;
-    int       iHiProd;
-    int       iCur;
-    SPLIT64   sdlTmp;
-    DECIMAL   decRes;
-    DECIMAL   decTmp;
-    LPDECIMAL pdecTmp;
-
-    bSign ^= (pdecR->u.u.sign ^ pdecL->u.u.sign) & DECIMAL_NEG;
-
-    if (pdecR->u.u.scale == pdecL->u.u.scale) {
-      // Scale factors are equal, no alignment necessary.
-      //
-      decRes.u.signscale = pdecL->u.signscale;
-
-AlignedAdd:
-      if (bSign) {
-        // Signs differ - subtract
-        //
-        DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecL) - DECIMAL_LO64_GET(*pdecR));
-        DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) - DECIMAL_HI32(*pdecR);
-
-        // Propagate carry
-        //
-        if (DECIMAL_LO64_GET(decRes) > DECIMAL_LO64_GET(*pdecL)) {
-          decRes.Hi32--;
-          if (decRes.Hi32 >= pdecL->Hi32)
-            goto SignFlip;
-        }
-        else if (decRes.Hi32 > pdecL->Hi32) {
-          // Got negative result.  Flip its sign.
-          //
-SignFlip:
-          DECIMAL_LO64_SET(decRes, -(LONGLONG)DECIMAL_LO64_GET(decRes));
-          decRes.Hi32 = ~decRes.Hi32;
-          if (DECIMAL_LO64_GET(decRes) == 0)
-            decRes.Hi32++;
-          decRes.u.u.sign ^= DECIMAL_NEG;
-        }
-
-      }
-      else {
-        // Signs are the same - add
-        //
-        DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecL) + DECIMAL_LO64_GET(*pdecR));
-        decRes.Hi32 = pdecL->Hi32 + pdecR->Hi32;
-
-        // Propagate carry
-        //
-        if (DECIMAL_LO64_GET(decRes) < DECIMAL_LO64_GET(*pdecL)) {
-          decRes.Hi32++;
-          if (decRes.Hi32 <= pdecL->Hi32)
-            goto AlignedScale;
-        }
-        else if (decRes.Hi32 < pdecL->Hi32) {
-AlignedScale:
-          // The addition carried above 96 bits.  Divide the result by 10,
-          // dropping the scale factor.
-          //
-          if (decRes.u.u.scale == 0)
-            return DISP_E_OVERFLOW;
-          decRes.u.u.scale--;
-
-          sdlTmp.u.Lo = decRes.Hi32;
-          sdlTmp.u.Hi = 1;
-          sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-          decRes.Hi32 = sdlTmp.u.Lo;
-
-          sdlTmp.u.Lo = decRes.v.v.Mid32;
-          sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-          decRes.v.v.Mid32 = sdlTmp.u.Lo;
-
-          sdlTmp.u.Lo = decRes.v.v.Lo32;
-          sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
-          decRes.v.v.Lo32 = sdlTmp.u.Lo;
-
-          // See if we need to round up.
-          //
-          if (sdlTmp.u.Hi >= 5 && (sdlTmp.u.Hi > 5 || (decRes.v.v.Lo32 & 1))) {
-            DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(decRes)+1)
-            if (DECIMAL_LO64_GET(decRes) == 0)
-              decRes.Hi32++;
-          }
-        }
-      }
-    }
-    else {
-      // Scale factors are not equal.  Assume that a larger scale
-      // factor (more decimal places) is likely to mean that number
-      // is smaller.  Start by guessing that the right operand has
-      // the larger scale factor.  The result will have the larger
-      // scale factor.
-      //
-      decRes.u.u.scale = pdecR->u.u.scale;  // scale factor of "smaller"
-      decRes.u.u.sign = pdecL->u.u.sign;    // but sign of "larger"
-      iScale = decRes.u.u.scale - pdecL->u.u.scale;
-
-      if (iScale < 0) {
-        // Guessed scale factor wrong. Swap operands.
-        //
-        iScale = -iScale;
-        decRes.u.u.scale = pdecL->u.u.scale;
-        decRes.u.u.sign ^= bSign;
-        pdecTmp = pdecR;
-        pdecR = pdecL;
-        pdecL = pdecTmp;
-      }
-
-      // *pdecL will need to be multiplied by 10^iScale so
-      // it will have the same scale as *pdecR.  We could be
-      // extending it to up to 192 bits of precision.
-      //
-      if (iScale <= POWER10_MAX) {
-        // Scaling won't make it larger than 4 ULONGs
-        //
-        ulPwr = rgulPower10[iScale];
-        DECIMAL_LO64_SET(decTmp, UInt32x32To64(pdecL->v.v.Lo32, ulPwr));
-        sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, ulPwr);
-        sdlTmp.int64 += decTmp.v.v.Mid32;
-        decTmp.v.v.Mid32 = sdlTmp.u.Lo;
-        decTmp.Hi32 = sdlTmp.u.Hi;
-        sdlTmp.int64 = UInt32x32To64(pdecL->Hi32, ulPwr);
-        sdlTmp.int64 += decTmp.Hi32;
-        if (sdlTmp.u.Hi == 0) {
-          // Result fits in 96 bits.  Use standard aligned add.
-          //
-          decTmp.Hi32 = sdlTmp.u.Lo;
-          pdecL = &decTmp;
-          goto AlignedAdd;
-        }
-        rgulNum[0] = decTmp.v.v.Lo32;
-        rgulNum[1] = decTmp.v.v.Mid32;
-        rgulNum[2] = sdlTmp.u.Lo;
-        rgulNum[3] = sdlTmp.u.Hi;
-        iHiProd = 3;
-      }
-      else {
-        // Have to scale by a bunch.  Move the number to a buffer
-        // where it has room to grow as it's scaled.
-        //
-        rgulNum[0] = pdecL->v.v.Lo32;
-        rgulNum[1] = pdecL->v.v.Mid32;
-        rgulNum[2] = pdecL->Hi32;
-        iHiProd = 2;
-
-        // Scan for zeros in the upper words.
-        //
-        if (rgulNum[2] == 0) {
-          iHiProd = 1;
-          if (rgulNum[1] == 0) {
-            iHiProd = 0;
-            if (rgulNum[0] == 0) {
-              // Left arg is zero, return right.
-              //
-              DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecR));
-              decRes.Hi32 = pdecR->Hi32;
-              decRes.u.u.sign ^= bSign;
-              goto RetDec;
-            }
-          }
-        }
-
-        // Scaling loop, up to 10^9 at a time.  iHiProd stays updated
-        // with index of highest non-zero ULONG.
-        //
-        for (; iScale > 0; iScale -= POWER10_MAX) {
-          if (iScale > POWER10_MAX)
-            ulPwr = ulTenToNine;
-          else
-            ulPwr = rgulPower10[iScale];
-
-          sdlTmp.u.Hi = 0;
-          for (iCur = 0; iCur <= iHiProd; iCur++) {
-            sdlTmp.int64 = UInt32x32To64(rgulNum[iCur], ulPwr) + sdlTmp.u.Hi;
-            rgulNum[iCur] = sdlTmp.u.Lo;
-          }
-
-          if (sdlTmp.u.Hi != 0)
-            // We're extending the result by another ULONG.
-            rgulNum[++iHiProd] = sdlTmp.u.Hi;
-        }
-      }
-
-      // Scaling complete, do the add.  Could be subtract if signs differ.
-      //
-      sdlTmp.u.Lo = rgulNum[0];
-      sdlTmp.u.Hi = rgulNum[1];
-
-      if (bSign) {
-        // Signs differ, subtract.
-        //
-        DECIMAL_LO64_SET(decRes, sdlTmp.int64 - DECIMAL_LO64_GET(*pdecR));
-        decRes.Hi32 = rgulNum[2] - pdecR->Hi32;
-
-        // Propagate carry
-        //
-        if (DECIMAL_LO64_GET(decRes) > sdlTmp.int64) {
-          decRes.Hi32--;
-          if (decRes.Hi32 >= rgulNum[2])
-            goto LongSub;
-        }
-        else if (decRes.Hi32 > rgulNum[2]) {
-LongSub:
-          // If rgulNum has more than 96 bits of precision, then we need to
-          // carry the subtraction into the higher bits.  If it doesn't,
-          // then we subtracted in the wrong order and have to flip the 
-          // sign of the result.
-          // 
-          if (iHiProd <= 2)
-            goto SignFlip;
-
-          iCur = 3;
-          while(rgulNum[iCur++]-- == 0);
-          if (rgulNum[iHiProd] == 0)
-            iHiProd--;
-        }
-      }
-      else {
-        // Signs the same, add.
-        //
-        DECIMAL_LO64_SET(decRes, sdlTmp.int64 + DECIMAL_LO64_GET(*pdecR));
-        decRes.Hi32 = rgulNum[2] + pdecR->Hi32;
-
-        // Propagate carry
-        //
-        if (DECIMAL_LO64_GET(decRes) < sdlTmp.int64) {
-          decRes.Hi32++;
-          if (decRes.Hi32 <= rgulNum[2])
-            goto LongAdd;
-        }
-        else if (decRes.Hi32 < rgulNum[2]) {
-LongAdd:
-          // Had a carry above 96 bits.
-          //
-          iCur = 3;
-          do {
-            if (iHiProd < iCur) {
-              rgulNum[iCur] = 1;
-              iHiProd = iCur;
-              break;
-            }
-          }while (++rgulNum[iCur++] == 0);
-        }
-      }
-
-      if (iHiProd > 2) {
-        rgulNum[0] = decRes.v.v.Lo32;
-        rgulNum[1] = decRes.v.v.Mid32;
-        rgulNum[2] = decRes.Hi32;
-        decRes.u.u.scale = ScaleResult(rgulNum, iHiProd, decRes.u.u.scale);
-        if (decRes.u.u.scale == (BYTE) -1)
-          return DISP_E_OVERFLOW;
-
-        decRes.v.v.Lo32 = rgulNum[0];
-        decRes.v.v.Mid32 = rgulNum[1];
-        decRes.Hi32 = rgulNum[2];
-      }
-    }
-
-RetDec:
-    COPYDEC(*pdecRes, decRes)
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecDiv - Decimal Divide
-//
-//**********************************************************************
-
-STDAPI VarDecDiv(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
-    ULONG   rgulQuo[3];
-    ULONG   rgulQuoSave[3];
-    ULONG   rgulRem[4];
-    ULONG   rgulDivisor[3];
-    ULONG   ulPwr;
-    ULONG   ulTmp;
-    ULONG   ulTmp1;
-    SPLIT64 sdlTmp;
-    SPLIT64 sdlDivisor;
-    int     iScale;
-    int     iCurScale;
-
-    iScale = pdecL->u.u.scale - pdecR->u.u.scale;
-    rgulDivisor[0] = pdecR->v.v.Lo32;
-    rgulDivisor[1] = pdecR->v.v.Mid32;
-    rgulDivisor[2] = pdecR->Hi32;
-
-    if (rgulDivisor[1] == 0 && rgulDivisor[2] == 0) {
-      // Divisor is only 32 bits.  Easy divide.
-      //
-      if (rgulDivisor[0] == 0)
-        return DISP_E_DIVBYZERO;
-
-      rgulQuo[0] = pdecL->v.v.Lo32;
-      rgulQuo[1] = pdecL->v.v.Mid32;
-      rgulQuo[2] = pdecL->Hi32;
-      rgulRem[0] = Div96By32(rgulQuo, rgulDivisor[0]);
-
-      for (;;) {
-        if (rgulRem[0] == 0) {
-          if (iScale < 0) {
-            iCurScale = min(9, -iScale);
-            goto HaveScale;
-          }
-          break;
-        }
-
-        // We have computed a quotient based on the natural scale 
-        // ( <dividend scale> - <divisor scale> ).  We have a non-zero 
-        // remainder, so now we should increase the scale if possible to 
-        // include more quotient bits.
-        // 
-        // If it doesn't cause overflow, we'll loop scaling by 10^9 and 
-        // computing more quotient bits as long as the remainder stays 
-        // non-zero.  If scaling by that much would cause overflow, we'll 
-        // drop out of the loop and scale by as much as we can.
-        // 
-        // Scaling by 10^9 will overflow if rgulQuo[2].rgulQuo[1] >= 2^32 / 10^9 
-        // = 4.294 967 296.  So the upper limit is rgulQuo[2] == 4 and 
-        // rgulQuo[1] == 0.294 967 296 * 2^32 = 1,266,874,889.7+.  Since 
-        // quotient bits in rgulQuo[0] could be all 1's, then 1,266,874,888 
-        // is the largest value in rgulQuo[1] (when rgulQuo[2] == 4) that is 
-        // assured not to overflow.
-        // 
-        iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], iScale);
-        if (iCurScale == 0) {
-          // No more scaling to be done, but remainder is non-zero.
-          // Round quotient.
-          //
-          ulTmp = rgulRem[0] << 1;
-          if (ulTmp < rgulRem[0] || (ulTmp >= rgulDivisor[0] &&
-              (ulTmp > rgulDivisor[0] || (rgulQuo[0] & 1)))) {
-RoundUp:
-            if (++rgulQuo[0] == 0)
-              if (++rgulQuo[1] == 0)
-                rgulQuo[2]++;
-          }
-          break;
-        }
-
-        if (iCurScale == -1)
-          return DISP_E_OVERFLOW;
-
-HaveScale:
-        ulPwr = rgulPower10[iCurScale];
-        iScale += iCurScale;
-
-        if (IncreaseScale(rgulQuo, ulPwr) != 0)
-          return DISP_E_OVERFLOW;
-
-        sdlTmp.int64 = DivMod64by32(UInt32x32To64(rgulRem[0], ulPwr), rgulDivisor[0]);
-        rgulRem[0] = sdlTmp.u.Hi;
-
-        rgulQuo[0] += sdlTmp.u.Lo;
-        if (rgulQuo[0] < sdlTmp.u.Lo) {
-          if (++rgulQuo[1] == 0)
-            rgulQuo[2]++;
-        }
-      } // for (;;)
-    }
-    else {
-      // Divisor has bits set in the upper 64 bits.
-      //
-      // Divisor must be fully normalized (shifted so bit 31 of the most 
-      // significant ULONG is 1).  Locate the MSB so we know how much to 
-      // normalize by.  The dividend will be shifted by the same amount so 
-      // the quotient is not changed.
-      //
-      if (rgulDivisor[2] == 0)
-        ulTmp = rgulDivisor[1];
-      else
-        ulTmp = rgulDivisor[2];
-
-      iCurScale = 0;
-      if (!(ulTmp & 0xFFFF0000)) {
-        iCurScale += 16;
-        ulTmp <<= 16;
-      }
-      if (!(ulTmp & 0xFF000000)) {
-        iCurScale += 8;
-        ulTmp <<= 8;
-      }
-      if (!(ulTmp & 0xF0000000)) {
-        iCurScale += 4;
-        ulTmp <<= 4;
-      }
-      if (!(ulTmp & 0xC0000000)) {
-        iCurScale += 2;
-        ulTmp <<= 2;
-      }
-      if (!(ulTmp & 0x80000000)) {
-        iCurScale++;
-        ulTmp <<= 1;
-      }
-    
-      // Shift both dividend and divisor left by iCurScale.
-      // 
-      sdlTmp.int64 = DECIMAL_LO64_GET(*pdecL) << iCurScale;
-      rgulRem[0] = sdlTmp.u.Lo;
-      rgulRem[1] = sdlTmp.u.Hi;
-      sdlTmp.u.Lo = pdecL->v.v.Mid32;
-      sdlTmp.u.Hi = pdecL->Hi32;
-      sdlTmp.int64 <<= iCurScale;
-      rgulRem[2] = sdlTmp.u.Hi;
-      rgulRem[3] = (pdecL->Hi32 >> (31 - iCurScale)) >> 1;
-
-      sdlDivisor.u.Lo = rgulDivisor[0];
-      sdlDivisor.u.Hi = rgulDivisor[1];
-      sdlDivisor.int64 <<= iCurScale;
-
-      if (rgulDivisor[2] == 0) {
-        // Have a 64-bit divisor in sdlDivisor.  The remainder
-        // (currently 96 bits spread over 4 ULONGs) will be < divisor.
-        //
-        sdlTmp.u.Lo = rgulRem[2];
-        sdlTmp.u.Hi = rgulRem[3];
-
-        rgulQuo[2] = 0;
-        rgulQuo[1] = Div96By64(&rgulRem[1], sdlDivisor);
-        rgulQuo[0] = Div96By64(rgulRem, sdlDivisor);
-
-        for (;;) {
-          if ((rgulRem[0] | rgulRem[1]) == 0) {
-            if (iScale < 0) {
-              iCurScale = min(9, -iScale);
-              goto HaveScale64;
-            }
-            break;
-          }
-
-          // Remainder is non-zero.  Scale up quotient and remainder by 
-          // powers of 10 so we can compute more significant bits.
-          // 
-          iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], iScale);
-          if (iCurScale == 0) {
-            // No more scaling to be done, but remainder is non-zero.
-            // Round quotient.
-            //
-            sdlTmp.u.Lo = rgulRem[0];
-            sdlTmp.u.Hi = rgulRem[1];
-            if (sdlTmp.u.Hi >= 0x80000000 || (sdlTmp.int64 <<= 1) > sdlDivisor.int64 ||
-                (sdlTmp.int64 == sdlDivisor.int64 && (rgulQuo[0] & 1)))
-              goto RoundUp;
-            break;
-          }
-
-          if (iCurScale == -1)
-            return DISP_E_OVERFLOW;
-
-HaveScale64:
-          ulPwr = rgulPower10[iCurScale];
-          iScale += iCurScale;
-
-          if (IncreaseScale(rgulQuo, ulPwr) != 0)
-            return DISP_E_OVERFLOW;
-
-          rgulRem[2] = 0;  // rem is 64 bits, IncreaseScale uses 96
-          IncreaseScale(rgulRem, ulPwr);
-          ulTmp = Div96By64(rgulRem, sdlDivisor);
-          rgulQuo[0] += ulTmp;
-          if (rgulQuo[0] < ulTmp)
-            if (++rgulQuo[1] == 0)
-              rgulQuo[2]++;
-
-        } // for (;;)
-      }
-      else {
-        // Have a 96-bit divisor in rgulDivisor[].
-        //
-        // Start by finishing the shift left by iCurScale.
-        //
-        sdlTmp.u.Lo = rgulDivisor[1];
-        sdlTmp.u.Hi = rgulDivisor[2];
-        sdlTmp.int64 <<= iCurScale;
-        rgulDivisor[0] = sdlDivisor.u.Lo;
-        rgulDivisor[1] = sdlDivisor.u.Hi;
-        rgulDivisor[2] = sdlTmp.u.Hi;
-
-        // The remainder (currently 96 bits spread over 4 ULONGs) 
-        // will be < divisor.
-        // 
-        rgulQuo[2] = 0;
-        rgulQuo[1] = 0;
-        rgulQuo[0] = Div128By96(rgulRem, rgulDivisor);
-
-        for (;;) {
-          if ((rgulRem[0] | rgulRem[1] | rgulRem[2]) == 0) {
-            if (iScale < 0) {
-              iCurScale = min(9, -iScale);
-              goto HaveScale96;
-            }
-            break;
-          }
-
-          // Remainder is non-zero.  Scale up quotient and remainder by 
-          // powers of 10 so we can compute more significant bits.
-          // 
-          iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], iScale);
-          if (iCurScale == 0) {
-            // No more scaling to be done, but remainder is non-zero.
-            // Round quotient.
-            //
-            if (rgulRem[2] >= 0x80000000)
-              goto RoundUp;
-
-            ulTmp = rgulRem[0] > 0x80000000;
-            ulTmp1 = rgulRem[1] > 0x80000000;
-            rgulRem[0] <<= 1;
-            rgulRem[1] = (rgulRem[1] << 1) + ulTmp;
-            rgulRem[2] = (rgulRem[2] << 1) + ulTmp1;
-
-            if (rgulRem[2] > rgulDivisor[2] || (rgulRem[2] == rgulDivisor[2] &&
-                (rgulRem[1] > rgulDivisor[1] || (rgulRem[1] == rgulDivisor[1] &&
-                (rgulRem[0] > rgulDivisor[0] || (rgulRem[0] == rgulDivisor[0] &&
-                (rgulQuo[0] & 1)))))))
-              goto RoundUp;
-            break;
-          }
-
-          if (iCurScale == -1)
-            return DISP_E_OVERFLOW;
-
-HaveScale96:
-          ulPwr = rgulPower10[iCurScale];
-          iScale += iCurScale;
-
-          if (IncreaseScale(rgulQuo, ulPwr) != 0)
-            return DISP_E_OVERFLOW;
-
-          rgulRem[3] = IncreaseScale(rgulRem, ulPwr);
-          ulTmp = Div128By96(rgulRem, rgulDivisor);
-          rgulQuo[0] += ulTmp;
-          if (rgulQuo[0] < ulTmp)
-            if (++rgulQuo[1] == 0)
-              rgulQuo[2]++;
-
-        } // for (;;)
-      }
-    }
-
-    // No more remainder.  Try extracting any extra powers of 10 we may have 
-    // added.  We do this by trying to divide out 10^8, 10^4, 10^2, and 10^1.
-    // If a division by one of these powers returns a zero remainder, then
-    // we keep the quotient.  If the remainder is not zero, then we restore
-    // the previous value.
-    // 
-    // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10
-    // we can extract.  We use this as a quick test on whether to try a
-    // given power.
-    // 
-    while ((rgulQuo[0] & 0xFF) == 0 && iScale >= 8) {
-      rgulQuoSave[0] = rgulQuo[0];
-      rgulQuoSave[1] = rgulQuo[1];
-      rgulQuoSave[2] = rgulQuo[2];
-
-      if (Div96By32(rgulQuoSave, 100000000) == 0) {
-        rgulQuo[0] = rgulQuoSave[0];
-        rgulQuo[1] = rgulQuoSave[1];
-        rgulQuo[2] = rgulQuoSave[2];
-        iScale -= 8;
-      }
-      else
-        break;
-    }
-
-    if ((rgulQuo[0] & 0xF) == 0 && iScale >= 4) {
-      rgulQuoSave[0] = rgulQuo[0];
-      rgulQuoSave[1] = rgulQuo[1];
-      rgulQuoSave[2] = rgulQuo[2];
-
-      if (Div96By32(rgulQuoSave, 10000) == 0) {
-        rgulQuo[0] = rgulQuoSave[0];
-        rgulQuo[1] = rgulQuoSave[1];
-        rgulQuo[2] = rgulQuoSave[2];
-        iScale -= 4;
-      }
-    }
-
-    if ((rgulQuo[0] & 3) == 0 && iScale >= 2) {
-      rgulQuoSave[0] = rgulQuo[0];
-      rgulQuoSave[1] = rgulQuo[1];
-      rgulQuoSave[2] = rgulQuo[2];
-
-      if (Div96By32(rgulQuoSave, 100) == 0) {
-        rgulQuo[0] = rgulQuoSave[0];
-        rgulQuo[1] = rgulQuoSave[1];
-        rgulQuo[2] = rgulQuoSave[2];
-        iScale -= 2;
-      }
-    }
-
-    if ((rgulQuo[0] & 1) == 0 && iScale >= 1) {
-      rgulQuoSave[0] = rgulQuo[0];
-      rgulQuoSave[1] = rgulQuo[1];
-      rgulQuoSave[2] = rgulQuo[2];
-
-      if (Div96By32(rgulQuoSave, 10) == 0) {
-        rgulQuo[0] = rgulQuoSave[0];
-        rgulQuo[1] = rgulQuoSave[1];
-        rgulQuo[2] = rgulQuoSave[2];
-        iScale -= 1;
-      }
-    }
-
-    pdecRes->Hi32 = rgulQuo[2];
-    pdecRes->v.v.Mid32 = rgulQuo[1];
-    pdecRes->v.v.Lo32 = rgulQuo[0];
-    pdecRes->u.u.scale = iScale;
-    pdecRes->u.u.sign = pdecL->u.u.sign ^ pdecR->u.u.sign;
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecAbs - Decimal Absolute Value
-//
-//**********************************************************************
-
-STDAPI VarDecAbs(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
-    COPYDEC(*pdecRes, *pdecOprd)
-    pdecRes->u.u.sign &= ~DECIMAL_NEG;
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecFix - Decimal Fix (chop to integer)
-//
-//**********************************************************************
-
-STDAPI VarDecFix(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
-    DecFixInt(pdecRes, pdecOprd);
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecInt - Decimal Int (round down to integer)
-//
-//**********************************************************************
-
-STDAPI VarDecInt(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
-    if (DecFixInt(pdecRes, pdecOprd) != 0 && (pdecRes->u.u.sign & DECIMAL_NEG)) {
-      // We have chopped off a non-zero amount from a negative value.  Since
-      // we round toward -infinity, we must increase the integer result by
-      // 1 to make it more negative.  This will never overflow because
-      // in order to have a remainder, we must have had a non-zero scale factor.
-      // Our scale factor is back to zero now.
-      //
-      DECIMAL_LO64_SET(*pdecRes, DECIMAL_LO64_GET(*pdecRes) + 1);
-      if (DECIMAL_LO64_GET(*pdecRes) == 0)
-        pdecRes->Hi32++;
-    }
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecNeg - Decimal Negate
-//
-//**********************************************************************
-
-STDAPI VarDecNeg(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
-    COPYDEC(*pdecRes, *pdecOprd)
-    pdecRes->u.u.sign ^= DECIMAL_NEG;
-    return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecCmp - Decimal Compare
-//
-//**********************************************************************
-
-STDAPI VarDecCmp(LPDECIMAL pdecL, LPDECIMAL pdecR)
-{
-    ULONG   ulSgnL;
-    ULONG   ulSgnR;
-
-    // First check signs and whether either are zero.  If both are
-    // non-zero and of the same sign, just use subtraction to compare.
-    //
-    ulSgnL = pdecL->v.v.Lo32 | pdecL->v.v.Mid32 | pdecL->Hi32;
-    ulSgnR = pdecR->v.v.Lo32 | pdecR->v.v.Mid32 | pdecR->Hi32;
-    if (ulSgnL != 0)
-      ulSgnL = (pdecL->u.u.sign & DECIMAL_NEG) | 1;
-
-    if (ulSgnR != 0)
-      ulSgnR = (pdecR->u.u.sign & DECIMAL_NEG) | 1;
-
-    // ulSgnL & ulSgnR have values 1, 0, or 0x81 depending on if the left/right
-    // operand is +, 0, or -.
-    //
-    if (ulSgnL == ulSgnR) {
-      if (ulSgnL == 0)    // both are zero
-        return VARCMP_EQ; // return equal
-
-      DECIMAL decRes;
-
-      DecAddSub(pdecL, pdecR, &decRes, DECIMAL_NEG);
-      if (DECIMAL_LO64_GET(decRes) == 0 && decRes.Hi32 == 0)
-        return VARCMP_EQ;
-      if (decRes.u.u.sign & DECIMAL_NEG)
-        return VARCMP_LT;
-      return VARCMP_GT;
-    }
-
-    // Signs are different.  Used signed byte compares
-    //
-    if ((char)ulSgnL > (char)ulSgnR)
-      return VARCMP_GT;
-    return VARCMP_LT;
-}
-
-STDAPI VarDecRound(LPDECIMAL pdecIn, int cDecimals, LPDECIMAL pdecRes)
-{
-    ULONG   rgulNum[3];
-    ULONG   ulRem;
-    ULONG   ulSticky;
-    ULONG   ulPwr;
-    int            iScale;
-
-    if (cDecimals < 0)
-      return E_INVALIDARG;
-
-    iScale = pdecIn->u.u.scale - cDecimals;
-    if (iScale > 0)
-    {
-      rgulNum[0] = pdecIn->v.v.Lo32;
-      rgulNum[1] = pdecIn->v.v.Mid32;
-      rgulNum[2] = pdecIn->Hi32;
-      pdecRes->u.u.sign = pdecIn->u.u.sign;
-      ulRem = ulSticky = 0;
-
-      do {
-       ulSticky |= ulRem;
-       if (iScale > POWER10_MAX)
-         ulPwr = ulTenToNine;
-       else
-         ulPwr = rgulPower10[iScale];
-
-       ulRem = Div96By32(rgulNum, ulPwr);
-       iScale -= 9;
-      }while (iScale > 0);
-
-      // Now round.  ulRem has last remainder, ulSticky has sticky bits.
-      // To do IEEE rounding, we add LSB of result to sticky bits so
-      // either causes round up if remainder * 2 == last divisor.
-      //
-      ulSticky |= rgulNum[0] & 1;
-      ulRem = (ulRem << 1) + (ulSticky != 0);
-      if (ulPwr < ulRem &&
-         ++rgulNum[0] == 0 &&
-         ++rgulNum[1] == 0
-        )
-       ++rgulNum[2];
-
-      pdecRes->v.v.Lo32 = rgulNum[0];
-      pdecRes->v.v.Mid32 = rgulNum[1];
-      pdecRes->Hi32 = rgulNum[2];
-      pdecRes->u.u.scale = cDecimals;
-      return NOERROR;
-    }
-
-    COPYDEC(*pdecRes, *pdecIn)
-    return NOERROR;
-}
diff --git a/src/coreclr/src/palrt/decconv.cpp b/src/coreclr/src/palrt/decconv.cpp
deleted file mode 100644 (file)
index 9cb7575..0000000
+++ /dev/null
@@ -1,602 +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: decconv.cpp
-// 
-// ===========================================================================
-/***
-*
-*Purpose:
-*  This module contains the low level conversion for Decimal data type.
-*
-*Implementation Notes:
-*
-*****************************************************************************/
-
-#include "common.h"
-#include "convert.h"
-
-#include <oleauto.h>
-#include <math.h>
-#include <limits.h>
-
-#define VALIDATEDECIMAL(dec) \
-    if (DECIMAL_SCALE(dec) > DECMAX || (DECIMAL_SIGN(dec) & ~DECIMAL_NEG) != 0) \
-        return E_INVALIDARG;
-
-#define RESULT(X)   ((HRESULT)(X))
-        
-//***********************************************************************
-//
-// Data tables
-//
-
-const double dblPower10[] = {
-    1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 
-    1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 
-    1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 
-    1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 
-    1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 
-    1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
-    1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69, 
-    1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
-    1e80 };
-
-double fnDblPower10(int ix)
-{
-    const int maxIx = (sizeof(dblPower10)/sizeof(dblPower10[0]));
-    _ASSERTE(ix >= 0);
-    if (ix < maxIx)
-        return dblPower10[ix];
-    return pow(10.0, ix);
-} // double fnDblPower10()
-
-#define DBLBIAS 1022
-#define SNGBIAS 126
-#define DECMAX 28
-
-const SPLIT64    sdlTenToEighteen = { UI64(1000000000000000000) };
-const DBLSTRUCT ds2to64 = DEFDS(0, 0, DBLBIAS + 65, 0);
-
-//***********************************************************************
-//
-// Data tables
-//
-
-const SPLIT64 sdlPower10[] = { {UI64(10000000000)},          // 1E10
-                          {UI64(100000000000)},     // 1E11
-                          {UI64(1000000000000)},    // 1E12
-                          {UI64(10000000000000)},   // 1E13
-                          {UI64(100000000000000)} }; // 1E14
-
-const unsigned __int64 ulPower10[] = {1,
-                    UI64(10),
-                    UI64(100),
-                    UI64(1000),
-                    UI64(10000),
-                    UI64(100000),
-                    UI64(1000000),
-                    UI64(10000000),
-                    UI64(100000000),
-                    UI64(1000000000),
-                    UI64(10000000000),
-                    UI64(100000000000),
-                    UI64(1000000000000),
-                    UI64(10000000000000),
-                    UI64(100000000000000),
-                    UI64(1000000000000000),
-                    UI64(10000000000000000),
-                    UI64(100000000000000000),
-                    UI64(1000000000000000000),
-                    UI64(10000000000000000000)};
-
-DWORDLONG UInt64x64To128(SPLIT64 sdlOp1, SPLIT64 sdlOp2, DWORDLONG *pdlHi)
-{
-    SPLIT64  sdlTmp1;
-    SPLIT64  sdlTmp2;
-    SPLIT64  sdlTmp3;
-
-    sdlTmp1.int64 = UInt32x32To64(sdlOp1.u.Lo, sdlOp2.u.Lo); // lo partial prod
-    sdlTmp2.int64 = UInt32x32To64(sdlOp1.u.Lo, sdlOp2.u.Hi); // mid 1 partial prod
-    sdlTmp1.u.Hi += sdlTmp2.u.Lo;
-    if (sdlTmp1.u.Hi < sdlTmp2.u.Lo)  // test for carry
-      sdlTmp2.u.Hi++;
-    sdlTmp3.int64 = UInt32x32To64(sdlOp1.u.Hi, sdlOp2.u.Hi) + (DWORDLONG)sdlTmp2.u.Hi;
-    sdlTmp2.int64 = UInt32x32To64(sdlOp1.u.Hi, sdlOp2.u.Lo);
-    sdlTmp1.u.Hi += sdlTmp2.u.Lo;
-    if (sdlTmp1.u.Hi < sdlTmp2.u.Lo)  // test for carry
-      sdlTmp2.u.Hi++;
-    sdlTmp3.int64 += (DWORDLONG)sdlTmp2.u.Hi;
-
-    *pdlHi = sdlTmp3.int64;
-    return sdlTmp1.int64;
-}
-
-                    
-//***********************************************************************
-//
-// Conversion to/from Decimal data type
-//
-
-
-STDAPI 
-VarDecFromR4(float fltIn, DECIMAL FAR* pdecOut)
-{
-    int         iExp;    // number of bits to left of binary point
-    int         iPower;
-    ULONG       ulMant;
-    double      dbl;
-    SPLIT64     sdlLo;
-    SPLIT64     sdlHi;
-    int         lmax, cur;  // temps used during scale reduction
-
-    // The most we can scale by is 10^28, which is just slightly more
-    // than 2^93.  So a float with an exponent of -94 could just
-    // barely reach 0.5, but smaller exponents will always round to zero.
-    //
-    if ( (iExp = ((SNGSTRUCT *)&fltIn)->exp - SNGBIAS) < -94 )
-    {
-      DECIMAL_SETZERO(*pdecOut);
-      return NOERROR;
-    }
-
-    if (iExp > 96)
-      return RESULT(DISP_E_OVERFLOW);
-
-    // Round the input to a 7-digit integer.  The R4 format has
-    // only 7 digits of precision, and we want to keep garbage digits
-    // out of the Decimal were making.
-    //
-    // Calculate max power of 10 input value could have by multiplying 
-    // the exponent by log10(2).  Using scaled integer multiplcation, 
-    // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
-    //
-    dbl = fabs(fltIn);
-    iPower = 6 - ((iExp * 19728) >> 16);
-
-    if (iPower >= 0) {
-      // We have less than 7 digits, scale input up.
-      //
-      if (iPower > DECMAX)
-        iPower = DECMAX;
-
-      dbl = dbl * dblPower10[iPower];
-    }
-    else {
-      if (iPower != -1 || dbl >= 1E7)
-        dbl = dbl / fnDblPower10(-iPower);
-      else 
-        iPower = 0; // didn't scale it
-    }
-
-    _ASSERTE(dbl < 1E7);
-    if (dbl < 1E6 && iPower < DECMAX)
-    {
-      dbl *= 10;
-      iPower++;
-      _ASSERTE(dbl >= 1E6);
-    }
-
-    // Round to integer
-    //
-    ulMant = (LONG)dbl;
-    dbl -= (double)ulMant;  // difference between input & integer
-    if ( dbl > 0.5 || (dbl == 0.5 && (ulMant & 1)) )
-      ulMant++;
-
-    if (ulMant == 0)
-    {
-      DECIMAL_SETZERO(*pdecOut);
-      return NOERROR;
-    }
-
-    if (iPower < 0) {
-      // Add -iPower factors of 10, -iPower <= (29 - 7) = 22.
-      //
-      iPower = -iPower;
-      if (iPower < 10) {
-        sdlLo.int64 = UInt32x32To64(ulMant, (ULONG)ulPower10[iPower]);
-
-        DECIMAL_LO32(*pdecOut) = sdlLo.u.Lo;
-        DECIMAL_MID32(*pdecOut) = sdlLo.u.Hi;
-        DECIMAL_HI32(*pdecOut) = 0;
-      }
-      else {
-        // Have a big power of 10.
-        //
-        if (iPower > 18) {
-          sdlLo.int64 = UInt32x32To64(ulMant, (ULONG)ulPower10[iPower - 18]);
-          sdlLo.int64 = UInt64x64To128(sdlLo, sdlTenToEighteen, &sdlHi.int64);
-
-          if (sdlHi.u.Hi != 0)
-            return RESULT(DISP_E_OVERFLOW);
-        }
-        else {
-          sdlLo.int64 = UInt32x32To64(ulMant, (ULONG)ulPower10[iPower - 9]);
-          sdlHi.int64 = UInt32x32To64(ulTenToNine, sdlLo.u.Hi);
-          sdlLo.int64 = UInt32x32To64(ulTenToNine, sdlLo.u.Lo);
-          sdlHi.int64 += sdlLo.u.Hi;
-          sdlLo.u.Hi = sdlHi.u.Lo;
-          sdlHi.u.Lo = sdlHi.u.Hi;
-        }
-        DECIMAL_LO32(*pdecOut) = sdlLo.u.Lo;
-        DECIMAL_MID32(*pdecOut) = sdlLo.u.Hi;
-        DECIMAL_HI32(*pdecOut) = sdlHi.u.Lo;
-      }
-      DECIMAL_SCALE(*pdecOut) = 0;
-    }
-    else {
-      // Factor out powers of 10 to reduce the scale, if possible.
-      // The maximum number we could factor out would be 6.  This
-      // comes from the fact we have a 7-digit number, and the
-      // MSD must be non-zero -- but the lower 6 digits could be
-      // zero.  Note also the scale factor is never negative, so
-      // we can't scale by any more than the power we used to
-      // get the integer.
-      //
-      // DivMod32by32 returns the quotient in Lo, the remainder in Hi.
-      //
-      lmax = min(iPower, 6);
-
-      // lmax is the largest power of 10 to try, lmax <= 6.
-      // We'll try powers 4, 2, and 1 unless they're too big.
-      //
-      for (cur = 4; cur > 0; cur >>= 1)
-      {
-        if (cur > lmax)
-          continue;
-
-        sdlLo.int64 = DivMod32by32(ulMant, (ULONG)ulPower10[cur]);
-
-        if (sdlLo.u.Hi == 0) {
-          ulMant = sdlLo.u.Lo;
-          iPower -= cur;
-          lmax -= cur;
-        }
-      }
-      DECIMAL_LO32(*pdecOut) = ulMant;
-      DECIMAL_MID32(*pdecOut) = 0;
-      DECIMAL_HI32(*pdecOut) = 0;
-      DECIMAL_SCALE(*pdecOut) = iPower;
-    }
-
-    DECIMAL_SIGN(*pdecOut) = (char)((SNGSTRUCT *)&fltIn)->sign << 7;
-    return NOERROR;
-}
-
-STDAPI 
-VarDecFromR8(double dblIn, DECIMAL FAR* pdecOut)
-{
-    int         iExp;    // number of bits to left of binary point
-    int         iPower;  // power-of-10 scale factor
-    SPLIT64     sdlMant;
-    SPLIT64     sdlLo;
-    double      dbl;
-    int         lmax, cur;  // temps used during scale reduction
-    ULONG       ulPwrCur;
-    ULONG       ulQuo;
-
-
-    // The most we can scale by is 10^28, which is just slightly more
-    // than 2^93.  So a float with an exponent of -94 could just
-    // barely reach 0.5, but smaller exponents will always round to zero.
-    //
-    if ( (iExp = ((DBLSTRUCT *)&dblIn)->u.exp - DBLBIAS) < -94 )
-    {
-      DECIMAL_SETZERO(*pdecOut);
-      return NOERROR;
-    }
-
-    if (iExp > 96)
-      return RESULT(DISP_E_OVERFLOW);
-
-    // Round the input to a 15-digit integer.  The R8 format has
-    // only 15 digits of precision, and we want to keep garbage digits
-    // out of the Decimal were making.
-    //
-    // Calculate max power of 10 input value could have by multiplying 
-    // the exponent by log10(2).  Using scaled integer multiplcation, 
-    // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
-    //
-    dbl = fabs(dblIn);
-    iPower = 14 - ((iExp * 19728) >> 16);
-
-    if (iPower >= 0) {
-      // We have less than 15 digits, scale input up.
-      //
-      if (iPower > DECMAX)
-        iPower = DECMAX;
-
-      dbl = dbl * dblPower10[iPower];
-    }
-    else {
-      if (iPower != -1 || dbl >= 1E15)
-        dbl = dbl / fnDblPower10(-iPower);
-      else 
-        iPower = 0; // didn't scale it
-    }
-
-    _ASSERTE(dbl < 1E15);
-    if (dbl < 1E14 && iPower < DECMAX)
-    {
-      dbl *= 10;
-      iPower++;
-      _ASSERTE(dbl >= 1E14);
-    }
-
-    // Round to int64
-    //
-    sdlMant.int64 = (LONGLONG)dbl;
-    dbl -= (double)(LONGLONG)sdlMant.int64;  // dif between input & integer
-    if ( dbl > 0.5 || (dbl == 0.5 && (sdlMant.u.Lo & 1)) )
-      sdlMant.int64++;
-
-    if (sdlMant.int64 == 0)
-    {
-      DECIMAL_SETZERO(*pdecOut);
-      return NOERROR;
-    }
-
-    if (iPower < 0) {
-      // Add -iPower factors of 10, -iPower <= (29 - 15) = 14.
-      //
-      iPower = -iPower;
-      if (iPower < 10) {
-        sdlLo.int64 = UInt32x32To64(sdlMant.u.Lo, (ULONG)ulPower10[iPower]);
-        sdlMant.int64 = UInt32x32To64(sdlMant.u.Hi, (ULONG)ulPower10[iPower]);
-        sdlMant.int64 += sdlLo.u.Hi;
-        sdlLo.u.Hi = sdlMant.u.Lo;
-        sdlMant.u.Lo = sdlMant.u.Hi;
-      }
-      else {
-        // Have a big power of 10.
-        //
-        _ASSERTE(iPower <= 14);
-        sdlLo.int64 = UInt64x64To128(sdlMant, sdlPower10[iPower-10], &sdlMant.int64);
-
-        if (sdlMant.u.Hi != 0)
-          return RESULT(DISP_E_OVERFLOW);
-      }
-      DECIMAL_LO32(*pdecOut) = sdlLo.u.Lo;
-      DECIMAL_MID32(*pdecOut) = sdlLo.u.Hi;
-      DECIMAL_HI32(*pdecOut) = sdlMant.u.Lo;
-      DECIMAL_SCALE(*pdecOut) = 0;
-    }
-    else {
-      // Factor out powers of 10 to reduce the scale, if possible.
-      // The maximum number we could factor out would be 14.  This
-      // comes from the fact we have a 15-digit number, and the 
-      // MSD must be non-zero -- but the lower 14 digits could be 
-      // zero.  Note also the scale factor is never negative, so
-      // we can't scale by any more than the power we used to
-      // get the integer.
-      //
-      // DivMod64by32 returns the quotient in Lo, the remainder in Hi.
-      //
-      lmax = min(iPower, 14);
-
-      // lmax is the largest power of 10 to try, lmax <= 14.
-      // We'll try powers 8, 4, 2, and 1 unless they're too big.
-      //
-      for (cur = 8; cur > 0; cur >>= 1)
-      {
-        if (cur > lmax)
-          continue;
-
-        ulPwrCur = (ULONG)ulPower10[cur];
-
-        if (sdlMant.u.Hi >= ulPwrCur) {
-          // Overflow if we try to divide in one step.
-          //
-          sdlLo.int64 = DivMod64by32(sdlMant.u.Hi, ulPwrCur);
-          ulQuo = sdlLo.u.Lo;
-          sdlLo.u.Lo = sdlMant.u.Lo;
-          sdlLo.int64 = DivMod64by32(sdlLo.int64, ulPwrCur);
-        }
-        else {
-          ulQuo = 0;
-          sdlLo.int64 = DivMod64by32(sdlMant.int64, ulPwrCur);
-        }
-
-        if (sdlLo.u.Hi == 0) {
-          sdlMant.u.Hi = ulQuo;
-          sdlMant.u.Lo = sdlLo.u.Lo;
-          iPower -= cur;
-          lmax -= cur;
-        }
-      }
-
-      DECIMAL_HI32(*pdecOut) = 0;
-      DECIMAL_SCALE(*pdecOut) = iPower;
-      DECIMAL_LO32(*pdecOut) = sdlMant.u.Lo;
-      DECIMAL_MID32(*pdecOut) = sdlMant.u.Hi;
-    }
-
-    DECIMAL_SIGN(*pdecOut) = (char)((DBLSTRUCT *)&dblIn)->u.sign << 7;
-    return NOERROR;
-}
-
-STDAPI
-VarDecFromCy(CY cyIn, DECIMAL FAR* pdecOut)
-{
-    DECIMAL_SIGN(*pdecOut) = (UCHAR)((cyIn.u.Hi >> 24) & DECIMAL_NEG);
-    if (DECIMAL_SIGN(*pdecOut))
-      cyIn.int64 = -cyIn.int64;
-
-    DECIMAL_LO32(*pdecOut) = cyIn.u.Lo;
-    DECIMAL_MID32(*pdecOut) = cyIn.u.Hi;
-    DECIMAL_SCALE(*pdecOut) = 4;
-    DECIMAL_HI32(*pdecOut) = 0;
-    return NOERROR;
-}
-
-STDAPI VarR4FromDec(DECIMAL FAR* pdecIn, float FAR* pfltOut)
-{
-    double   dbl;
-
-    VALIDATEDECIMAL(*pdecIn); // E_INVALIDARG check
-
-    // Can't overflow; no errors possible.
-    //
-    VarR8FromDec(pdecIn, &dbl);
-    *pfltOut = (float)dbl;
-    return NOERROR;
-}
-
-STDAPI VarR8FromDec(DECIMAL FAR* pdecIn, double FAR* pdblOut)
-{
-    SPLIT64  sdlTmp;
-    double   dbl;
-
-    VALIDATEDECIMAL(*pdecIn); // E_INVALIDARG check
-
-    sdlTmp.u.Lo = DECIMAL_LO32(*pdecIn);
-    sdlTmp.u.Hi = DECIMAL_MID32(*pdecIn);
-
-    if ( (LONG)DECIMAL_MID32(*pdecIn) < 0 )
-      dbl = (ds2to64.dbl + (double)(LONGLONG)sdlTmp.int64 +
-             (double)DECIMAL_HI32(*pdecIn) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*pdecIn)) ;
-    else
-      dbl = ((double)(LONGLONG)sdlTmp.int64 +
-             (double)DECIMAL_HI32(*pdecIn) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*pdecIn));
-
-    if (DECIMAL_SIGN(*pdecIn))
-      dbl = -dbl;
-
-    *pdblOut = dbl;
-    return NOERROR;
-}
-
-STDAPI VarCyFromDec(DECIMAL FAR* pdecIn, CY FAR* pcyOut)
-{
-    SPLIT64  sdlTmp;
-    SPLIT64  sdlTmp1;
-    int      scale;
-    ULONG    ulPwr;
-    ULONG    ul;
-
-    VALIDATEDECIMAL(*pdecIn); // E_INVALIDARG check
-
-    scale = DECIMAL_SCALE(*pdecIn) - 4;  // the power of 10 to divide by
-
-    if (scale == 0) {
-      // No scaling needed -- the Decimal has 4 decimal places,
-      // just what Currency needs.
-      //
-      if ( DECIMAL_HI32(*pdecIn) != 0 ||
-          (DECIMAL_MID32(*pdecIn) >= 0x80000000 &&
-          (DECIMAL_MID32(*pdecIn) != 0x80000000 || DECIMAL_LO32(*pdecIn) != 0 || !DECIMAL_SIGN(*pdecIn))) )
-        return RESULT(DISP_E_OVERFLOW);
-
-      sdlTmp.u.Lo = DECIMAL_LO32(*pdecIn);
-      sdlTmp.u.Hi = DECIMAL_MID32(*pdecIn);
-
-      if (DECIMAL_SIGN(*pdecIn))
-        pcyOut->int64 = -(LONGLONG)sdlTmp.int64;
-      else
-        pcyOut->int64 = sdlTmp.int64;
-      return NOERROR;
-    }
-
-    // Need to scale to get 4 decimal places.  -4 <= scale <= 24.
-    //
-    if (scale < 0) {
-      sdlTmp1.int64 = UInt32x32To64((ULONG)ulPower10[-scale], DECIMAL_MID32(*pdecIn));
-      sdlTmp.int64 = UInt32x32To64((ULONG)ulPower10[-scale], DECIMAL_LO32(*pdecIn));
-      sdlTmp.u.Hi += sdlTmp1.u.Lo;
-      if (DECIMAL_HI32(*pdecIn) != 0 || sdlTmp1.u.Hi != 0 || sdlTmp1.u.Lo > sdlTmp.u.Hi)
-        return RESULT(DISP_E_OVERFLOW);
-    }
-    else if (scale < 10) {
-      // DivMod64by32 returns the quotient in Lo, the remainder in Hi.
-      //
-      ulPwr = (ULONG)ulPower10[scale];
-      if (DECIMAL_HI32(*pdecIn) >= ulPwr)
-        return RESULT(DISP_E_OVERFLOW);
-      sdlTmp1.u.Lo = DECIMAL_MID32(*pdecIn);
-      sdlTmp1.u.Hi = DECIMAL_HI32(*pdecIn);
-      sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulPwr);
-      sdlTmp.u.Hi = sdlTmp1.u.Lo;    // quotient to high half of result
-      sdlTmp1.u.Lo = DECIMAL_LO32(*pdecIn); // extended remainder
-      sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulPwr);
-      sdlTmp.u.Lo = sdlTmp1.u.Lo;    // quotient to low half of result
-
-      // Round result based on remainder in sdlTmp1.Hi.
-      //
-      ulPwr >>= 1;  // compare to power/2 (power always even)
-      if (sdlTmp1.u.Hi > ulPwr || (sdlTmp1.u.Hi == ulPwr && (sdlTmp.u.Lo & 1)))
-        sdlTmp.int64++;
-    }
-    else {
-      // We have a power of 10 in the range 10 - 24.  These powers do
-      // not fit in 32 bits.  We'll handle this by scaling 2 or 3 times,
-      // first by 10^10, then by the remaining amount (or 10^9, then
-      // the last bit).
-      //
-      // To scale by 10^10, we'll actually divide by 10^10/4, which fits
-      // in 32 bits.  The second scaling is multiplied by four
-      // to account for it, just barely assured of fitting in 32 bits
-      // (4E9 < 2^32).  Note that the upper third of the quotient is
-      // either zero or one, so we skip the divide step to calculate it.  
-      // (Max 4E9 divided by 2.5E9.)
-      //
-      // DivMod64by32 returns the quotient in Lo, the remainder in Hi.
-      //
-      if (DECIMAL_HI32(*pdecIn) >= ulTenToTenDiv4) {
-        sdlTmp.u.Hi = 1;                // upper 1st quotient
-        sdlTmp1.u.Hi = DECIMAL_HI32(*pdecIn) - ulTenToTenDiv4;  // remainder
-      }
-      else {
-        sdlTmp.u.Hi = 0;                // upper 1st quotient
-        sdlTmp1.u.Hi = DECIMAL_HI32(*pdecIn);    // remainder
-      }
-      sdlTmp1.u.Lo = DECIMAL_MID32(*pdecIn);     // extended remainder
-      sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulTenToTenDiv4);
-      sdlTmp.u.Lo = sdlTmp1.u.Lo;         // middle 1st quotient
-
-      sdlTmp1.u.Lo = DECIMAL_LO32(*pdecIn);      // extended remainder
-      sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulTenToTenDiv4);
-
-      ulPwr = (ULONG)(ulPower10[min(scale-10, 9)] << 2);
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
-      ul = sdlTmp.u.Lo;                 // upper 2nd quotient
-
-      sdlTmp.u.Lo = sdlTmp1.u.Lo;         // extended remainder
-      sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
-      sdlTmp1.u.Lo = sdlTmp.u.Hi;         // save final remainder
-      sdlTmp.u.Hi = ul;                 // position high result
-
-      if (scale >= 20) {
-        ulPwr = (ULONG)(ulPower10[scale-19]);
-        sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
-        sdlTmp1.u.Hi |= sdlTmp1.u.Lo;     // combine sticky bits
-        sdlTmp1.u.Lo = sdlTmp.u.Hi;       // final remainder
-        sdlTmp.u.Hi = 0;                // guaranteed result fits in 32 bits
-      }
-
-      // Round result based on remainder in sdlTmp1.Lo.  sdlTmp1.Hi is
-      // the remainder from the first division(s), representing sticky bits.
-      // Current result is in sdlTmp.
-      //
-      ulPwr >>= 1;  // compare to power/2 (power always even)
-      if (sdlTmp1.u.Lo > ulPwr || (sdlTmp1.u.Lo == ulPwr &&
-                       ((sdlTmp.u.Lo & 1) || sdlTmp1.u.Hi != 0)))
-        sdlTmp.int64++;
-    }
-
-    if (sdlTmp.u.Hi >= 0x80000000 &&
-        (sdlTmp.int64 != UI64(0x8000000000000000) || !DECIMAL_SIGN(*pdecIn)))
-      return RESULT(DISP_E_OVERFLOW);
-
-    if (DECIMAL_SIGN(*pdecIn))
-      sdlTmp.int64 = -(LONGLONG)sdlTmp.int64;
-
-    pcyOut->int64 = sdlTmp.int64;
-    return NOERROR;
-}
-
-
index 8ee51b4..25bc85a 100644 (file)
@@ -740,7 +740,6 @@ FCFuncEnd()
 FCFuncStart(gNumberFuncs)
     FCFuncElement("DoubleToNumber", COMNumber::DoubleToNumberFC)
     FCFuncElement("NumberToDouble", COMNumber::NumberToDoubleFC)
-    FCFuncElement("NumberBufferToDecimal", COMNumber::NumberBufferToDecimal)
 FCFuncEnd()
 
 #ifdef FEATURE_COMINTEROP
@@ -760,26 +759,6 @@ FCFuncStart(gOAVariantFuncs)
 FCFuncEnd()
 #endif // FEATURE_COMINTEROP
 
-FCFuncStart(gDecimalFuncs)
-    FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_Flt_RetVoid, COMDecimal::InitSingle)
-    FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_Dbl_RetVoid, COMDecimal::InitDouble)
-    FCFuncElement("FCallAddSub", COMDecimal::DoAddSubThrow)
-    FCFuncElement("FCallMultiply", COMDecimal::DoMultiplyThrow)
-    FCFuncElement("FCallDivide", COMDecimal::DoDivideThrow)
-    FCFuncElement("FCallCompare", COMDecimal::DoCompare)
-    FCFuncElement("FCallFloor", COMDecimal::DoFloor)
-    FCFuncElement("FCallRound", COMDecimal::DoRound)
-    FCFuncElement("FCallToCurrency", COMDecimal::DoToCurrency)
-    FCFuncElement("FCallToInt32", COMDecimal::ToInt32)    
-    FCFuncElement("ToDouble", COMDecimal::ToDouble)
-    FCFuncElement("ToSingle", COMDecimal::ToSingle)
-    FCFuncElement("FCallTruncate", COMDecimal::DoTruncate)
-FCFuncEnd()
-
-FCFuncStart(gCurrencyFuncs)
-    FCFuncElement("FCallToDecimal", COMCurrency::DoToDecimal)
-FCFuncEnd()
-
 FCFuncStart(gClrConfig)
     QCFuncElement("GetConfigBoolValue", ClrConfigNative::GetConfigBoolValue)
 FCFuncEnd()
@@ -1122,7 +1101,6 @@ FCFuncStart(gStubHelperFuncs)
     FCFuncElement("ProfilerEndTransitionCallback", StubHelpers::ProfilerEndTransitionCallback)
 #endif    
     FCFuncElement("CreateCustomMarshalerHelper", StubHelpers::CreateCustomMarshalerHelper)
-    FCFuncElement("DecimalCanonicalizeInternal", StubHelpers::DecimalCanonicalizeInternal)
     FCFuncElement("FmtClassUpdateNativeInternal", StubHelpers::FmtClassUpdateNativeInternal)
     FCFuncElement("FmtClassUpdateCLRInternal", StubHelpers::FmtClassUpdateCLRInternal)
     FCFuncElement("LayoutDestroyNativeInternal", StubHelpers::LayoutDestroyNativeInternal)
@@ -1269,13 +1247,11 @@ FCClassElement("Buffer", "System", gBufferFuncs)
 FCClassElement("CLRConfig", "System", gClrConfig)
 FCClassElement("CompatibilitySwitch", "System.Runtime.Versioning", gCompatibilitySwitchFuncs)
 FCClassElement("CriticalHandle", "System.Runtime.InteropServices", gCriticalHandleFuncs)
-FCClassElement("Currency", "System", gCurrencyFuncs)
 FCClassElement("CustomAttribute", "System.Reflection", gCOMCustomAttributeFuncs)
 FCClassElement("CustomAttributeEncodedArgument", "System.Reflection", gCustomAttributeEncodedArgument)
 FCClassElement("DateMarshaler", "System.StubHelpers", gDateMarshalerFuncs)
 FCClassElement("DateTime", "System", gDateTimeFuncs)
 FCClassElement("Debugger", "System.Diagnostics", gDiagnosticsDebugger)
-FCClassElement("Decimal", "System", gDecimalFuncs)
 FCClassElement("DefaultBinder", "System", gCOMDefaultBinderFuncs)
 FCClassElement("Delegate", "System", gDelegateFuncs)
 FCClassElement("DependentHandle", "System.Runtime.CompilerServices", gDependentHandleFuncs)
index 1015657..50f12a8 100644 (file)
@@ -4200,12 +4200,7 @@ VOID FieldMarshaler_Currency::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pC
     // no need to switch to preemptive mode because it's very primitive operaion, doesn't take 
     // long and is guaranteed not to call 3rd party code. 
     // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
-    HRESULT hr = VarDecFromCy( *(CURRENCY*)pNative, (DECIMAL *)pCLR );
-    if (FAILED(hr))
-        COMPlusThrowHR(hr);
-
-    if (FAILED(DecimalCanonicalize((DECIMAL*)pCLR)))
-        COMPlusThrow(kOverflowException, W("Overflow_Currency"));
+    VarDecFromCyCanonicalize( *(CURRENCY*)pNative, (DECIMAL *)pCLR );
 }
 
 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
index a72276e..11b3e0b 100644 (file)
@@ -1332,11 +1332,6 @@ void ILCurrencyMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit
     EmitLoadNativeValue(pslILEmit);
 
     pslILEmit->EmitCALL(METHOD__DECIMAL__CURRENCY_CTOR, 2, 0);
-
-    EmitLoadManagedHomeAddr(pslILEmit);
-
-    // static void System.StubHelpers.DecimalCanonicalizeInternal(ref Decimal dec);
-    pslILEmit->EmitCALL(METHOD__STUBHELPERS__DECIMAL_CANONICALIZE_INTERNAL, 1, 0);
 }    
 
 
index 6cd93ad..a526ebd 100644 (file)
@@ -41,8 +41,6 @@
 #include "comsynchronizable.h"
 #include "floatdouble.h"
 #include "floatsingle.h"
-#include "decimal.h"
-#include "currency.h"
 #include "comdatetime.h"
 #include "number.h"
 #include "compatibilityswitch.h"
index c57290f..d6caea2 100644 (file)
@@ -1041,7 +1041,6 @@ DEFINE_METHOD(STUBHELPERS,          GET_HR_EXCEPTION_OBJECT, GetHRExceptionObjec
 DEFINE_METHOD(STUBHELPERS,          CREATE_CUSTOM_MARSHALER_HELPER, CreateCustomMarshalerHelper, SM_IntPtr_Int_IntPtr_RetIntPtr)
 
 DEFINE_METHOD(STUBHELPERS,          CHECK_STRING_LENGTH,    CheckStringLength,          SM_Int_RetVoid)
-DEFINE_METHOD(STUBHELPERS,          DECIMAL_CANONICALIZE_INTERNAL, DecimalCanonicalizeInternal,   SM_RefDec_RetVoid)
 
 DEFINE_METHOD(STUBHELPERS,          FMT_CLASS_UPDATE_NATIVE_INTERNAL,   FmtClassUpdateNativeInternal,   SM_Obj_PtrByte_RefCleanupWorkList_RetVoid)
 DEFINE_METHOD(STUBHELPERS,          FMT_CLASS_UPDATE_CLR_INTERNAL,      FmtClassUpdateCLRInternal,      SM_Obj_PtrByte_RetVoid)
index 4f62be6..330710b 100644 (file)
@@ -3770,11 +3770,7 @@ void OleVariant::MarshalCurrencyVariantOleToCom(VARIANT *pOleVariant,
     DECIMAL DecVal;
 
     // Convert the currency to a decimal.
-    HRESULT hr = VarDecFromCy(V_CY(pOleVariant), &DecVal);
-    IfFailThrow(hr);
-
-    if (FAILED(DecimalCanonicalize(&DecVal)))
-        COMPlusThrow(kOverflowException, W("Overflow_Currency"));
+    VarDecFromCyCanonicalize(V_CY(pOleVariant), &DecVal);
 
     // Store the value into the unboxes decimal and store the decimal in the variant.
     *(DECIMAL *) pDecimalRef->UnBox() = DecVal;   
@@ -3822,11 +3818,7 @@ void OleVariant::MarshalCurrencyVariantOleRefToCom(VARIANT *pOleVariant,
     DECIMAL DecVal;
 
     // Convert the currency to a decimal.
-    HRESULT hr = VarDecFromCy(*V_CYREF(pOleVariant), &DecVal);
-    IfFailThrow(hr);
-
-    if (FAILED(DecimalCanonicalize(&DecVal)))
-        COMPlusThrow(kOverflowException, W("Overflow_Currency"));
+    VarDecFromCyCanonicalize(*V_CYREF(pOleVariant), &DecVal);
 
     // Store the value into the unboxes decimal and store the decimal in the variant.
     *(DECIMAL *) pDecimalRef->UnBox() = DecVal;   
@@ -3856,11 +3848,7 @@ void OleVariant::MarshalCurrencyArrayOleToCom(void *oleArray, BASEARRAYREF *pCom
 
     while (pOle < pOleEnd)
     {
-        IfFailThrow(VarDecFromCy(*pOle++, pCom));
-        if (FAILED(DecimalCanonicalize(pCom)))
-            COMPlusThrow(kOverflowException, W("Overflow_Currency"));
-
-        pCom++;
+        VarDecFromCyCanonicalize(*pOle++, pCom++);
     }
 }
 
index 7475d98..0be8be3 100644 (file)
@@ -1696,17 +1696,6 @@ FCIMPL1(Object*, StubHelpers::AllocateInternal, EnregisteredTypeHandle pRegister
 }
 FCIMPLEND
 
-FCIMPL1(void, StubHelpers::DecimalCanonicalizeInternal, DECIMAL *pDec)
-{
-    FCALL_CONTRACT;
-
-    if (FAILED(DecimalCanonicalize(pDec)))
-    {
-        FCThrowResVoid(kOverflowException, W("Overflow_Currency"));
-    }
-}
-FCIMPLEND
-
 FCIMPL1(int, StubHelpers::AnsiStrlen, __in_z char* pszStr)
 {
     FCALL_CONTRACT;
index 560e0b3..e5376f7 100644 (file)
@@ -99,7 +99,6 @@ public:
 
     static FCDECL3(void*,           CreateCustomMarshalerHelper, MethodDesc* pMD, mdToken paramToken, TypeHandle hndManagedType);
 
-    static FCDECL1(void,            DecimalCanonicalizeInternal, DECIMAL *pDec);
     static FCDECL3(void,            FmtClassUpdateNativeInternal, Object* pObjUNSAFE, BYTE* pbNative, OBJECTREF *ppCleanupWorkListOnStack);
     static FCDECL2(void,            FmtClassUpdateCLRInternal, Object* pObjUNSAFE, BYTE* pbNative);
     static FCDECL2(void,            LayoutDestroyNativeInternal, BYTE* pbNative, MethodTable* pMT);
index 526e136..743a703 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\DateTimeOffset.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\DayOfWeek.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\DBNull.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Decimal.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Decimal.DecCalc.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\DefaultBinder.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\CodeAnalysis\SuppressMessageAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\ConditionalAttribute.cs" />
diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs
new file mode 100644 (file)
index 0000000..75ddbfc
--- /dev/null
@@ -0,0 +1,2711 @@
+// 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.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Internal.Runtime.CompilerServices;
+using X86 = System.Runtime.Intrinsics.X86;
+
+namespace System
+{
+    public partial struct Decimal
+    {
+        // Low level accessors used by a DecCalc and formatting
+        internal uint High => (uint)hi;
+        internal uint Low => (uint)lo;
+        internal uint Mid => (uint)mid;
+
+        internal bool IsNegative => flags < 0;
+
+        internal int Scale => (byte)(flags >> ScaleShift);
+
+#if BIGENDIAN
+        private ulong Low64 => ((ulong)Mid << 32) | Low;
+#else
+        private ulong Low64 => Unsafe.As<int, ulong>(ref Unsafe.AsRef(in lo));
+#endif
+
+        private static ref DecCalc AsMutable(ref decimal d) => ref Unsafe.As<decimal, DecCalc>(ref d);
+
+        #region APIs need by number formatting.
+
+        internal static uint DecDivMod1E9(ref decimal value)
+        {
+            return DecCalc.DecDivMod1E9(ref AsMutable(ref value));
+        }
+
+        internal static void DecAddInt32(ref decimal value, uint i)
+        {
+            DecCalc.DecAddInt32(ref AsMutable(ref value), i);
+        }
+
+        internal static void DecMul10(ref decimal value)
+        {
+            DecCalc.DecMul10(ref AsMutable(ref value));
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Class that contains all the mathematical calculations for decimal. Most of which have been ported from oleaut32.
+        /// </summary>
+        [StructLayout(LayoutKind.Explicit)]
+        private struct DecCalc
+        {
+            // NOTE: Do not change the offsets of these fields. This structure must have the same layout as Decimal.
+            [FieldOffset(0)]
+            private uint uflags;
+            [FieldOffset(4)]
+            private uint uhi;
+            [FieldOffset(8)]
+            private uint ulo;
+            [FieldOffset(12)]
+            private uint umid;
+
+            /// <summary>
+            /// The low and mid fields combined in little-endian order
+            /// </summary>
+            [FieldOffset(8)]
+            private ulong ulomidLE;
+
+            private uint High
+            {
+                get => uhi;
+                set => uhi = value;
+            }
+
+            private uint Low
+            {
+                get => ulo;
+                set => ulo = value;
+            }
+
+            private uint Mid
+            {
+                get => umid;
+                set => umid = value;
+            }
+
+            private bool IsNegative => (int)uflags < 0;
+
+            private int Scale => (byte)(uflags >> ScaleShift);
+
+            private ulong Low64
+            {
+#if BIGENDIAN
+                get { return ((ulong)umid << 32) | ulo; }
+                set { umid = (uint)(value >> 32); ulo = (uint)value; }
+#else
+                get => ulomidLE;
+                set => ulomidLE = value;
+#endif
+            }
+
+            private const uint SignMask = 0x80000000;
+            private const uint ScaleMask = 0x00FF0000;
+
+            private const int DEC_SCALE_MAX = 28;
+
+            private const uint TenToPowerNine = 1000000000;
+            private const ulong TenToPowerEighteen = 1000000000000000000;
+
+            // The maximum power of 10 that a 32 bit integer can store
+            private const int MaxInt32Scale = 9;
+            // The maximum power of 10 that a 64 bit integer can store
+            private const int MaxInt64Scale = 19;
+
+            // Fast access for 10^n where n is 0-9
+            private static readonly uint[] s_powers10 = new uint[] {
+                1,
+                10,
+                100,
+                1000,
+                10000,
+                100000,
+                1000000,
+                10000000,
+                100000000,
+                1000000000
+            };
+
+            // Fast access for 10^n where n is 1-19
+            private static readonly ulong[] s_ulongPowers10 = new ulong[] {
+                10,
+                100,
+                1000,
+                10000,
+                100000,
+                1000000,
+                10000000,
+                100000000,
+                1000000000,
+                10000000000,
+                100000000000,
+                1000000000000,
+                10000000000000,
+                100000000000000,
+                1000000000000000,
+                10000000000000000,
+                100000000000000000,
+                1000000000000000000,
+                10000000000000000000,
+            };
+
+            private static readonly double[] s_doublePowers10 = new double[] {
+                1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+                1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+                1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
+                1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
+                1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
+                1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
+                1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
+                1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
+                1e80
+            };
+
+            #region Decimal Math Helpers
+
+            private static unsafe uint GetExponent(float f)
+            {
+                // Based on pulling out the exp from this single struct layout
+                //typedef struct {
+                //    ULONG mant:23;
+                //    ULONG exp:8;
+                //    ULONG sign:1;
+                //} SNGSTRUCT;
+
+                return (byte)(*(uint*)&f >> 23);
+            }
+
+            private static unsafe uint GetExponent(double d)
+            {
+                // Based on pulling out the exp from this double struct layout
+                //typedef struct {
+                //   DWORDLONG mant:52;
+                //   DWORDLONG signexp:12;
+                // } DBLSTRUCT;
+
+                return (uint)(*(ulong*)&d >> 52) & 0x7FFu;
+            }
+
+            private static ulong UInt32x32To64(uint a, uint b)
+            {
+                return (ulong)a * (ulong)b;
+            }
+
+            private static void UInt64x64To128(ulong a, ulong b, ref DecCalc pdecOut)
+            {
+                ulong low = UInt32x32To64((uint)a, (uint)b); // lo partial prod
+                ulong mid = UInt32x32To64((uint)a, (uint)(b >> 32)); // mid 1 partial prod
+                ulong high = UInt32x32To64((uint)(a >> 32), (uint)(b >> 32));
+                high += mid >> 32;
+                low += mid <<= 32;
+                if (low < mid)  // test for carry
+                    high++;
+
+                mid = UInt32x32To64((uint)(a >> 32), (uint)b);
+                high += mid >> 32;
+                low += mid <<= 32;
+                if (low < mid)  // test for carry
+                    high++;
+
+                if (high > uint.MaxValue)
+                    throw new OverflowException(SR.Overflow_Decimal);
+                pdecOut.Low64 = low;
+                pdecOut.High = (uint)high;
+            }
+
+            /***
+             * Div96By32
+             *
+             * Entry:
+             *   bufNum - 96-bit dividend as array of ULONGs, least-sig first
+             *   ulDen   - 32-bit divisor.
+             *
+             * Purpose:
+             *   Do full divide, yielding 96-bit result and 32-bit remainder.
+             *
+             * Exit:
+             *   Quotient overwrites dividend.
+             *   Returns remainder.
+             *
+             * Exceptions:
+             *   None.
+             *
+             ***********************************************************************/
+            private static uint Div96By32(ref Buf12 bufNum, uint ulDen)
+            {
+                // TODO: https://github.com/dotnet/coreclr/issues/3439
+                ulong tmp, div;
+                if (bufNum.U2 != 0)
+                {
+                    tmp = bufNum.High64;
+                    div = tmp / ulDen;
+                    bufNum.High64 = div;
+                    tmp = ((tmp - (uint)div * ulDen) << 32) | bufNum.U0;
+                    if (tmp == 0)
+                        return 0;
+                    uint div32 = (uint)(tmp / ulDen);
+                    bufNum.U0 = div32;
+                    return (uint)tmp - div32 * ulDen;
+                }
+
+                tmp = bufNum.Low64;
+                if (tmp == 0)
+                    return 0;
+                div = tmp / ulDen;
+                bufNum.Low64 = div;
+                return (uint)(tmp - div * ulDen);
+            }
+
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private static bool Div96ByConst(ref ulong high64, ref uint low, uint pow)
+            {
+#if BIT64
+                ulong div64 = high64 / pow;
+                uint div = (uint)((((high64 - div64 * pow) << 32) + low) / pow);
+                if (low == div * pow)
+                {
+                    high64 = div64;
+                    low = div;
+                    return true;
+                }
+#else
+                // 32-bit RyuJIT doesn't convert 64-bit division by constant into multiplication by reciprocal. Do half-width divisions instead.
+                Debug.Assert(pow <= ushort.MaxValue);
+                uint num, mid32, low16, div;
+                if (high64 <= uint.MaxValue)
+                {
+                    num = (uint)high64;
+                    mid32 = num / pow;
+                    num = (num - mid32 * pow) << 16;
+
+                    num += low >> 16;
+                    low16 = num / pow;
+                    num = (num - low16 * pow) << 16;
+
+                    num += (ushort)low;
+                    div = num / pow;
+                    if (num == div * pow)
+                    {
+                        high64 = mid32;
+                        low = (low16 << 16) + div;
+                        return true;
+                    }
+                }
+                else
+                {
+                    num = (uint)(high64 >> 32);
+                    uint high32 = num / pow;
+                    num = (num - high32 * pow) << 16;
+
+                    num += (uint)high64 >> 16;
+                    mid32 = num / pow;
+                    num = (num - mid32 * pow) << 16;
+
+                    num += (ushort)high64;
+                    div = num / pow;
+                    num = (num - div * pow) << 16;
+                    mid32 = div + (mid32 << 16);
+
+                    num += low >> 16;
+                    low16 = num / pow;
+                    num = (num - low16 * pow) << 16;
+
+                    num += (ushort)low;
+                    div = num / pow;
+                    if (num == div * pow)
+                    {
+                        high64 = ((ulong)high32 << 32) | mid32;
+                        low = (low16 << 16) + div;
+                        return true;
+                    }
+                }
+#endif
+                return false;
+            }
+
+            // Normalize (unscale) the number by trying to divide out 10^8, 10^4, 10^2, and 10^1.
+            // If a division by one of these powers returns a zero remainder, then we keep the quotient.
+            //
+            // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10 we can extract.
+            // We use this as a quick test on whether to try a given power.
+            //
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private static void Unscale(ref uint low, ref ulong high64, ref int scale)
+            {
+#if BIT64
+                while ((byte)low == 0 && scale >= 8 && Div96ByConst(ref high64, ref low, 100000000))
+                    scale -= 8;
+
+                if ((low & 0xF) == 0 && scale >= 4 && Div96ByConst(ref high64, ref low, 10000))
+                    scale -= 4;
+#else
+                while ((low & 0xF) == 0 && scale >= 4 && Div96ByConst(ref high64, ref low, 10000))
+                    scale -= 4;
+#endif
+
+                if ((low & 3) == 0 && scale >= 2 && Div96ByConst(ref high64, ref low, 100))
+                    scale -= 2;
+
+                if ((low & 1) == 0 && scale >= 1 && Div96ByConst(ref high64, ref low, 10))
+                    scale--;
+            }
+
+            /***
+             * Div96By64
+             *
+             * Entry:
+             *   bufNum - 96-bit dividend as array of ULONGs, least-sig first
+             *   sdlDen  - 64-bit divisor.
+             *
+             * Purpose:
+             *   Do partial divide, yielding 32-bit result and 64-bit remainder.
+             *   Divisor must be larger than upper 64 bits of dividend.
+             *
+             * Exit:
+             *   Remainder overwrites lower 64-bits of dividend.
+             *   Returns quotient.
+             *
+             * Exceptions:
+             *   None.
+             *
+             ***********************************************************************/
+            private static uint Div96By64(ref Buf12 bufNum, ulong den)
+            {
+                uint quo;
+                ulong num;
+                uint num2 = bufNum.U2;
+                if (num2 == 0)
+                {
+                    num = bufNum.Low64;
+                    if (num < den)
+                        // Result is zero.  Entire dividend is remainder.
+                        return 0;
+
+                    // TODO: https://github.com/dotnet/coreclr/issues/3439
+                    quo = (uint)(num / den);
+                    num -= quo * den; // remainder
+                    bufNum.Low64 = num;
+                    return quo;
+                }
+
+                uint denHigh32 = (uint)(den >> 32);
+                if (num2 >= denHigh32)
+                {
+                    // Divide would overflow.  Assume a quotient of 2^32, and set
+                    // up remainder accordingly.
+                    //
+                    num = bufNum.Low64;
+                    num -= den << 32;
+                    quo = 0;
+
+                    // Remainder went negative.  Add divisor back in until it's positive,
+                    // a max of 2 times.
+                    //
+                    do
+                    {
+                        quo--;
+                        num += den;
+                    } while (num >= den);
+
+                    bufNum.Low64 = num;
+                    return quo;
+                }
+
+                // Hardware divide won't overflow
+                //
+                ulong num64 = bufNum.High64;
+                if (num64 < denHigh32)
+                    // Result is zero.  Entire dividend is remainder.
+                    //
+                    return 0;
+
+                // TODO: https://github.com/dotnet/coreclr/issues/3439
+                quo = (uint)(num64 / denHigh32);
+                num = bufNum.U0 | ((num64 - quo * denHigh32) << 32); // remainder
+
+                // Compute full remainder, rem = dividend - (quo * divisor).
+                //
+                ulong prod = UInt32x32To64(quo, (uint)den); // quo * lo divisor
+                num -= prod;
+
+                if (num > ~prod)
+                {
+                    // Remainder went negative.  Add divisor back in until it's positive,
+                    // a max of 2 times.
+                    //
+                    do
+                    {
+                        quo--;
+                        num += den;
+                    } while (num >= den);
+                }
+
+                bufNum.Low64 = num;
+                return quo;
+            }
+
+            /***
+             * Div128By96
+             *
+             * Entry:
+             *   bufNum - 128-bit dividend as array of ULONGs, least-sig first
+             *   bufDen - 96-bit divisor.
+             *
+             * Purpose:
+             *   Do partial divide, yielding 32-bit result and 96-bit remainder.
+             *   Top divisor ULONG must be larger than top dividend ULONG.  This is
+             *   assured in the initial call because the divisor is normalized
+             *   and the dividend can't be.  In subsequent calls, the remainder
+             *   is multiplied by 10^9 (max), so it can be no more than 1/4 of
+             *   the divisor which is effectively multiplied by 2^32 (4 * 10^9).
+             *
+             * Exit:
+             *   Remainder overwrites lower 96-bits of dividend.
+             *   Returns quotient.
+             *
+             * Exceptions:
+             *   None.
+             *
+             ***********************************************************************/
+            private static uint Div128By96(ref Buf16 bufNum, ref Buf12 bufDen)
+            {
+                ulong dividend = bufNum.High64;
+                uint den = bufDen.U2;
+                if (dividend < den)
+                    // Result is zero.  Entire dividend is remainder.
+                    //
+                    return 0;
+
+                // TODO: https://github.com/dotnet/coreclr/issues/3439
+                uint quo = (uint)(dividend / den);
+                uint remainder = (uint)dividend - quo * den;
+
+                // Compute full remainder, rem = dividend - (quo * divisor).
+                //
+                ulong prod1 = UInt32x32To64(quo, bufDen.U0); // quo * lo divisor
+                ulong prod2 = UInt32x32To64(quo, bufDen.U1); // quo * mid divisor
+                prod2 += prod1 >> 32;
+                prod1 = (uint)prod1 | (prod2 << 32);
+                prod2 >>= 32;
+
+                ulong num = bufNum.Low64;
+                num -= prod1;
+                remainder -= (uint)prod2;
+
+                // Propagate carries
+                //
+                if (num > ~prod1)
+                {
+                    remainder--;
+                    if (remainder < ~(uint)prod2)
+                        goto PosRem;
+                }
+                else if (remainder <= ~(uint)prod2)
+                    goto PosRem;
+                {
+                    // Remainder went negative.  Add divisor back in until it's positive,
+                    // a max of 2 times.
+                    //
+                    prod1 = bufDen.Low64;
+
+                    for (;;)
+                    {
+                        quo--;
+                        num += prod1;
+                        remainder += den;
+
+                        if (num < prod1)
+                        {
+                            // Detected carry. Check for carry out of top
+                            // before adding it in.
+                            //
+                            if (remainder++ < den)
+                                break;
+                        }
+                        if (remainder < den)
+                            break; // detected carry
+                    }
+                }
+PosRem:
+
+                bufNum.Low64 = num;
+                bufNum.U2 = remainder;
+                return quo;
+            }
+
+            /***
+             * IncreaseScale
+             *
+             * Entry:
+             *   bufNum - 96-bit number as array of ULONGs, least-sig first
+             *   ulPwr   - Scale factor to multiply by
+             *
+             * Purpose:
+             *   Multiply the two numbers.  The low 96 bits of the result overwrite
+             *   the input.  The last 32 bits of the product are the return value.
+             *
+             * Exit:
+             *   Returns highest 32 bits of product.
+             *
+             * Exceptions:
+             *   None.
+             *
+             ***********************************************************************/
+            private static uint IncreaseScale(ref Buf12 bufNum, uint ulPwr)
+            {
+                ulong tmp = UInt32x32To64(bufNum.U0, ulPwr);
+                bufNum.U0 = (uint)tmp;
+                tmp >>= 32;
+                tmp += UInt32x32To64(bufNum.U1, ulPwr);
+                bufNum.U1 = (uint)tmp;
+                tmp >>= 32;
+                tmp += UInt32x32To64(bufNum.U2, ulPwr);
+                bufNum.U2 = (uint)tmp;
+                return (uint)(tmp >> 32);
+            }
+
+            private static void IncreaseScale64(ref Buf12 bufNum, uint ulPwr)
+            {
+                ulong tmp = UInt32x32To64(bufNum.U0, ulPwr);
+                bufNum.U0 = (uint)tmp;
+                tmp >>= 32;
+                tmp += UInt32x32To64(bufNum.U1, ulPwr);
+                bufNum.High64 = tmp;
+            }
+
+            /***
+            * ScaleResult
+            *
+            * Entry:
+            *   bufRes - Array of ULONGs with value, least-significant first.
+            *   iHiRes  - Index of last non-zero value in bufRes.
+            *   iScale  - Scale factor for this value, range 0 - 2 * DEC_SCALE_MAX
+            *
+            * Purpose:
+            *   See if we need to scale the result to fit it in 96 bits.
+            *   Perform needed scaling.  Adjust scale factor accordingly.
+            *
+            * Exit:
+            *   bufRes updated in place, always 3 ULONGs.
+            *   New scale factor returned.
+            *
+            ***********************************************************************/
+            private static unsafe int ScaleResult(Buf24* bufRes, uint iHiRes, int iScale)
+            {
+                Debug.Assert(iHiRes < bufRes->Length);
+                uint* rgulRes = (uint*)bufRes;
+
+                // See if we need to scale the result.  The combined scale must
+                // be <= DEC_SCALE_MAX and the upper 96 bits must be zero.
+                //
+                // Start by figuring a lower bound on the scaling needed to make
+                // the upper 96 bits zero.  iHiRes is the index into rgulRes[]
+                // of the highest non-zero ULONG.
+                //
+                int iNewScale = 0;
+                if (iHiRes > 2)
+                {
+                    iNewScale = (int)iHiRes * 32 - 64 - 1;
+                    iNewScale -= X86.Lzcnt.IsSupported ? (int)X86.Lzcnt.LeadingZeroCount(rgulRes[iHiRes]) : LeadingZeroCount(rgulRes[iHiRes]);
+
+                    // Multiply bit position by log10(2) to figure it's power of 10.
+                    // We scale the log by 256.  log(2) = .30103, * 256 = 77.  Doing this
+                    // with a multiply saves a 96-byte lookup table.  The power returned
+                    // is <= the power of the number, so we must add one power of 10
+                    // to make it's integer part zero after dividing by 256.
+                    //
+                    // Note: the result of this multiplication by an approximation of
+                    // log10(2) have been exhaustively checked to verify it gives the
+                    // correct result.  (There were only 95 to check...)
+                    //
+                    iNewScale = ((iNewScale * 77) >> 8) + 1;
+
+                    // iNewScale = min scale factor to make high 96 bits zero, 0 - 29.
+                    // This reduces the scale factor of the result.  If it exceeds the
+                    // current scale of the result, we'll overflow.
+                    //
+                    if (iNewScale > iScale)
+                        goto ThrowOverflow;
+                }
+
+                // Make sure we scale by enough to bring the current scale factor
+                // into valid range.
+                //
+                if (iNewScale < iScale - DEC_SCALE_MAX)
+                    iNewScale = iScale - DEC_SCALE_MAX;
+
+                if (iNewScale != 0)
+                {
+                    // Scale by the power of 10 given by iNewScale.  Note that this is
+                    // NOT guaranteed to bring the number within 96 bits -- it could
+                    // be 1 power of 10 short.
+                    //
+                    iScale -= iNewScale;
+                    uint ulSticky = 0;
+                    uint quotient, remainder = 0;
+
+                    for (;;)
+                    {
+                        ulSticky |= remainder; // record remainder as sticky bit
+
+                        uint ulPwr;
+                        // Scaling loop specialized for each power of 10 because division by constant is an order of magnitude faster (especially for 64-bit division that's actually done by 128bit DIV on x64)
+                        switch (iNewScale)
+                        {
+                            case 1:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 10);
+                                break;
+                            case 2:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 100);
+                                break;
+                            case 3:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 1000);
+                                break;
+                            case 4:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 10000);
+                                break;
+#if BIT64
+                            case 5:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 100000);
+                                break;
+                            case 6:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 1000000);
+                                break;
+                            case 7:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 10000000);
+                                break;
+                            case 8:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, 100000000);
+                                break;
+                            default:
+                                ulPwr = DivByConst(rgulRes, iHiRes, out quotient, out remainder, TenToPowerNine);
+                                break;
+#else
+                            default:
+                                goto case 4;
+#endif
+                        }
+                        rgulRes[iHiRes] = quotient;
+                        // If first quotient was 0, update iHiRes.
+                        //
+                        if (quotient == 0 && iHiRes != 0)
+                            iHiRes--;
+
+#if BIT64
+                        iNewScale -= MaxInt32Scale;
+#else
+                        iNewScale -= 4;
+#endif
+                        if (iNewScale > 0)
+                            continue; // scale some more
+
+                        // If we scaled enough, iHiRes would be 2 or less.  If not,
+                        // divide by 10 more.
+                        //
+                        if (iHiRes > 2)
+                        {
+                            if (iScale == 0)
+                                goto ThrowOverflow;
+                            iNewScale = 1;
+                            iScale--;
+                            continue; // scale by 10
+                        }
+
+                        // Round final result.  See if remainder >= 1/2 of divisor.
+                        // If remainder == 1/2 divisor, round up if odd or sticky bit set.
+                        //
+                        ulPwr >>= 1;  // power of 10 always even
+                        if (ulPwr <= remainder && (ulPwr < remainder || ((rgulRes[0] & 1) | ulSticky) != 0) && ++rgulRes[0] == 0)
+                        {
+                            uint iCur = 0;
+                            do
+                            {
+                                Debug.Assert(iCur + 1 < bufRes->Length);
+                            }
+                            while (++rgulRes[++iCur] == 0);
+
+                            if (iCur > 2)
+                            {
+                                // The rounding caused us to carry beyond 96 bits.
+                                // Scale by 10 more.
+                                //
+                                if (iScale == 0)
+                                    goto ThrowOverflow;
+                                iHiRes = iCur;
+                                ulSticky = 0;  // no sticky bit
+                                remainder = 0; // or remainder
+                                iNewScale = 1;
+                                iScale--;
+                                continue; // scale by 10
+                            }
+                        }
+
+                        break;
+                    } // for(;;)
+                }
+                return iScale;
+
+ThrowOverflow:
+                throw new OverflowException(SR.Overflow_Decimal);
+            }
+
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private static unsafe uint DivByConst(uint* rgulRes, uint iHiRes, out uint quotient, out uint remainder, uint power)
+            {
+                uint high = rgulRes[iHiRes];
+                remainder = high - (quotient = high / power) * power;
+                for (uint i = iHiRes - 1; (int)i >= 0; i--)
+                {
+#if BIT64
+                    ulong num = rgulRes[i] + ((ulong)remainder << 32);
+                    remainder = (uint)num - (rgulRes[i] = (uint)(num / power)) * power;
+#else
+                    // 32-bit RyuJIT doesn't convert 64-bit division by constant into multiplication by reciprocal. Do half-width divisions instead.
+                    Debug.Assert(power <= ushort.MaxValue);
+#if BIGENDIAN
+                    const int low16 = 2, high16 = 0;
+#else
+                    const int low16 = 0, high16 = 2;
+#endif
+                    // byte* is used here because Roslyn doesn't do constant propagation for pointer arithmetic
+                    uint num = *(ushort*)((byte*)rgulRes + i * 4 + high16) + (remainder << 16);
+                    uint div = num / power;
+                    remainder = num - div * power;
+                    *(ushort*)((byte*)rgulRes + i * 4 + high16) = (ushort)div;
+
+                    num = *(ushort*)((byte*)rgulRes + i * 4 + low16) + (remainder << 16);
+                    div = num / power;
+                    remainder = num - div * power;
+                    *(ushort*)((byte*)rgulRes + i * 4 + low16) = (ushort)div;
+#endif
+                }
+                return power;
+            }
+
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private static int LeadingZeroCount(uint value)
+            {
+                Debug.Assert(value > 0);
+                int c = 1;
+                if ((value & 0xFFFF0000) == 0)
+                {
+                    value <<= 16;
+                    c += 16;
+                }
+                if ((value & 0xFF000000) == 0)
+                {
+                    value <<= 8;
+                    c += 8;
+                }
+                if ((value & 0xF0000000) == 0)
+                {
+                    value <<= 4;
+                    c += 4;
+                }
+                if ((value & 0xC0000000) == 0)
+                {
+                    value <<= 2;
+                    c += 2;
+                }
+                return c + ((int)value >> 31);
+            }
+
+            // Adjust the quotient to deal with an overflow. We need to divide by 10,
+            // feed in the high bit to undo the overflow and then round as required,
+            private static int OverflowUnscale(ref Buf12 bufQuo, int iScale, bool fRemainder)
+            {
+                if (--iScale < 0)
+                    throw new OverflowException(SR.Overflow_Decimal);
+
+                Debug.Assert(bufQuo.U2 == 0);
+
+                // We have overflown, so load the high bit with a one.
+                const ulong highbit = 1UL << 32;
+                bufQuo.U2 = (uint)(highbit / 10);
+                ulong tmp = ((highbit % 10) << 32) + bufQuo.U1;
+                uint div = (uint)(tmp / 10);
+                bufQuo.U1 = div;
+                tmp = ((tmp - div * 10) << 32) + bufQuo.U0;
+                div = (uint)(tmp / 10);
+                bufQuo.U0 = div;
+                uint remainder = (uint)(tmp - div * 10);
+                // The remainder is the last digit that does not fit, so we can use it to work out if we need to round up
+                if (remainder > 5 || remainder == 5 && (fRemainder || (bufQuo.U0 & 1) != 0))
+                    Add32To96(ref bufQuo, 1);
+                return iScale;
+            }
+
+            /***
+            * SearchScale
+            *
+            * Entry:
+            *   bufQuo - 96-bit quotient
+            *   iScale  - Scale factor of quotient, range -DEC_SCALE_MAX to DEC_SCALE_MAX-1
+            *
+            * Purpose:
+            *   Determine the max power of 10, <= 9, that the quotient can be scaled
+            *   up by and still fit in 96 bits.
+            *
+            * Exit:
+            *   Returns power of 10 to scale by.
+            *
+            ***********************************************************************/
+            private static int SearchScale(ref Buf12 bufQuo, int iScale)
+            {
+                const uint OVFL_MAX_9_HI = 4;
+                const uint OVFL_MAX_8_HI = 42;
+                const uint OVFL_MAX_7_HI = 429;
+                const uint OVFL_MAX_6_HI = 4294;
+                const uint OVFL_MAX_5_HI = 42949;
+                const uint OVFL_MAX_4_HI = 429496;
+                const uint OVFL_MAX_3_HI = 4294967;
+                const uint OVFL_MAX_2_HI = 42949672;
+                const uint OVFL_MAX_1_HI = 429496729;
+                const ulong OVFL_MAX_9_MIDLO = 5441186219426131129;
+
+                uint ulResHi = bufQuo.U2;
+                ulong ulResMidLo = bufQuo.Low64;
+                int iCurScale = 0;
+
+                // Quick check to stop us from trying to scale any more.
+                //
+                if (ulResHi > OVFL_MAX_1_HI)
+                {
+                    goto HaveScale;
+                }
+
+                var powerOvfl = PowerOvflValues;
+                if (iScale > DEC_SCALE_MAX - 9)
+                {
+                    // We can't scale by 10^9 without exceeding the max scale factor.
+                    // See if we can scale to the max.  If not, we'll fall into
+                    // standard search for scale factor.
+                    //
+                    iCurScale = DEC_SCALE_MAX - iScale;
+                    if (ulResHi < powerOvfl[iCurScale - 1].Hi)
+                        goto HaveScale;
+                }
+                else if (ulResHi < OVFL_MAX_9_HI || ulResHi == OVFL_MAX_9_HI && ulResMidLo <= OVFL_MAX_9_MIDLO)
+                    return 9;
+
+                // Search for a power to scale by < 9.  Do a binary search.
+                //
+                if (ulResHi > OVFL_MAX_5_HI)
+                {
+                    if (ulResHi > OVFL_MAX_3_HI)
+                    {
+                        iCurScale = 2;
+                        if (ulResHi > OVFL_MAX_2_HI)
+                            iCurScale--;
+                    }
+                    else
+                    {
+                        iCurScale = 4;
+                        if (ulResHi > OVFL_MAX_4_HI)
+                            iCurScale--;
+                    }
+                }
+                else
+                {
+                    if (ulResHi > OVFL_MAX_7_HI)
+                    {
+                        iCurScale = 6;
+                        if (ulResHi > OVFL_MAX_6_HI)
+                            iCurScale--;
+                    }
+                    else
+                    {
+                        iCurScale = 8;
+                        if (ulResHi > OVFL_MAX_8_HI)
+                            iCurScale--;
+                    }
+                }
+
+                // In all cases, we already found we could not use the power one larger.
+                // So if we can use this power, it is the biggest, and we're done.  If
+                // we can't use this power, the one below it is correct for all cases
+                // unless it's 10^1 -- we might have to go to 10^0 (no scaling).
+                //
+                if (ulResHi == powerOvfl[iCurScale - 1].Hi && ulResMidLo > powerOvfl[iCurScale - 1].MidLo)
+                    iCurScale--;
+
+                HaveScale:
+                // iCurScale = largest power of 10 we can scale by without overflow,
+                // iCurScale < 9.  See if this is enough to make scale factor
+                // positive if it isn't already.
+                //
+                if (iCurScale + iScale < 0)
+                    throw new OverflowException(SR.Overflow_Decimal);
+
+                return iCurScale;
+            }
+
+            // Add a 32 bit unsigned long to an array of 3 unsigned longs representing a 96 integer
+            // Returns false if there is an overflow
+            private static bool Add32To96(ref Buf12 bufNum, uint ulValue)
+            {
+                if ((bufNum.Low64 += ulValue) < ulValue)
+                {
+                    if (++bufNum.U2 == 0)
+                        return false;
+                }
+                return true;
+            }
+
+            // DecAddSub adds or subtracts two decimal values.
+            // On return, d1 contains the result of the operation and d2 is trashed.
+            // Passing in true for bSign means subtract and false means add.
+            internal static unsafe void DecAddSub(ref DecCalc d1, ref DecCalc d2, bool bSign)
+            {
+                ulong low64 = d1.Low64;
+                uint high = d1.High, flags = d1.uflags, d2flags = d2.uflags;
+
+                uint xorflags = d2flags ^ flags;
+                bSign ^= (xorflags & SignMask) != 0;
+
+                if ((xorflags & ScaleMask) == 0)
+                {
+                    // Scale factors are equal, no alignment necessary.
+                    //
+                    goto AlignedAdd;
+                }
+                else
+                {
+                    // Scale factors are not equal.  Assume that a larger scale
+                    // factor (more decimal places) is likely to mean that number
+                    // is smaller.  Start by guessing that the right operand has
+                    // the larger scale factor.  The result will have the larger
+                    // scale factor.
+                    //
+                    uint d1flags = flags;
+                    flags = d2flags & ScaleMask | flags & SignMask; // scale factor of "smaller",  but sign of "larger"
+                    int iScale = (int)(flags - d1flags) >> ScaleShift;
+
+                    if (iScale < 0)
+                    {
+                        // Guessed scale factor wrong. Swap operands.
+                        //
+                        iScale = -iScale;
+                        flags = d1flags;
+                        if (bSign)
+                            flags ^= SignMask;
+                        low64 = d2.Low64;
+                        high = d2.High;
+                        d2 = d1;
+                    }
+
+                    uint ulPwr;
+                    ulong tmp64, tmpLow;
+
+                    // d1 will need to be multiplied by 10^iScale so
+                    // it will have the same scale as d2.  We could be
+                    // extending it to up to 192 bits of precision.
+
+                    // Scan for zeros in the upper words.
+                    //
+                    if (high == 0)
+                    {
+                        if (low64 <= uint.MaxValue)
+                        {
+                            if ((uint)low64 == 0)
+                            {
+                                // Left arg is zero, return right.
+                                //
+                                uint signFlags = flags & SignMask;
+                                if (bSign)
+                                    signFlags ^= SignMask;
+                                d1 = d2;
+                                d1.uflags = d2.uflags & ScaleMask | signFlags;
+                                return;
+                            }
+
+                            do
+                            {
+                                if (iScale <= MaxInt32Scale)
+                                {
+                                    low64 = UInt32x32To64((uint)low64, s_powers10[iScale]);
+                                    goto AlignedAdd;
+                                }
+                                iScale -= MaxInt32Scale;
+                                low64 = UInt32x32To64((uint)low64, TenToPowerNine);
+                            } while (low64 <= uint.MaxValue);
+                        }
+
+                        do
+                        {
+                            ulPwr = TenToPowerNine;
+                            if (iScale < MaxInt32Scale)
+                                ulPwr = s_powers10[iScale];
+                            tmpLow = UInt32x32To64((uint)low64, ulPwr);
+                            tmp64 = UInt32x32To64((uint)(low64 >> 32), ulPwr) + (tmpLow >> 32);
+                            low64 = (uint)tmpLow + (tmp64 << 32);
+                            high = (uint)(tmp64 >> 32);
+                            if ((iScale -= MaxInt32Scale) <= 0)
+                                goto AlignedAdd;
+                        } while (high == 0);
+                    }
+
+                    while (true)
+                    {
+                        // Scaling won't make it larger than 4 ULONGs
+                        //
+                        ulPwr = TenToPowerNine;
+                        if (iScale < MaxInt32Scale)
+                            ulPwr = s_powers10[iScale];
+                        tmpLow = UInt32x32To64((uint)low64, ulPwr);
+                        tmp64 = UInt32x32To64((uint)(low64 >> 32), ulPwr) + (tmpLow >> 32);
+                        low64 = (uint)tmpLow + (tmp64 << 32);
+                        tmp64 >>= 32;
+                        tmp64 += UInt32x32To64(high, ulPwr);
+
+                        iScale -= MaxInt32Scale;
+                        if (tmp64 > uint.MaxValue)
+                            break;
+
+                        high = (uint)tmp64;
+                        // Result fits in 96 bits.  Use standard aligned add.
+                        if (iScale <= 0)
+                            goto AlignedAdd;
+                    }
+
+                    // Have to scale by a bunch. Move the number to a buffer where it has room to grow as it's scaled.
+                    //
+                    Buf24 bufNum;
+                    _ = &bufNum; // workaround for CS0165
+                    bufNum.Low64 = low64;
+                    bufNum.Mid64 = tmp64;
+                    uint iHiProd = 3;
+
+                    // Scaling loop, up to 10^9 at a time. iHiProd stays updated with index of highest non-zero ULONG.
+                    //
+                    for (; iScale > 0; iScale -= MaxInt32Scale)
+                    {
+                        ulPwr = TenToPowerNine;
+                        if (iScale < MaxInt32Scale)
+                            ulPwr = s_powers10[iScale];
+                        tmp64 = 0;
+                        uint* rgulNum = (uint*)&bufNum;
+                        for (uint iCur = 0; ;)
+                        {
+                            Debug.Assert(iCur < bufNum.Length);
+                            tmp64 += UInt32x32To64(rgulNum[iCur], ulPwr);
+                            rgulNum[iCur] = (uint)tmp64;
+                            iCur++;
+                            tmp64 >>= 32;
+                            if (iCur > iHiProd)
+                                break;
+                        }
+
+                        if ((uint)tmp64 != 0)
+                        {
+                            // We're extending the result by another ULONG.
+                            Debug.Assert(iHiProd + 1 < bufNum.Length);
+                            rgulNum[++iHiProd] = (uint)tmp64;
+                        }
+                    }
+
+                    // Scaling complete, do the add.  Could be subtract if signs differ.
+                    //
+                    tmp64 = bufNum.Low64;
+                    low64 = d2.Low64;
+                    uint tmpHigh = bufNum.U2;
+                    high = d2.High;
+
+                    if (bSign)
+                    {
+                        // Signs differ, subtract.
+                        //
+                        low64 = tmp64 - low64;
+                        high = tmpHigh - high;
+
+                        // Propagate carry
+                        //
+                        if (low64 > tmp64)
+                        {
+                            high--;
+                            if (high < tmpHigh)
+                                goto NoCarry;
+                        }
+                        else if (high <= tmpHigh)
+                            goto NoCarry;
+
+                        // Carry the subtraction into the higher bits.
+                        // 
+                        uint* rgulNum = (uint*)&bufNum;
+                        uint iCur = 3;
+                        do
+                        {
+                            Debug.Assert(iCur < bufNum.Length);
+                        } while (rgulNum[iCur++]-- == 0);
+                        Debug.Assert(iHiProd < bufNum.Length);
+                        if (rgulNum[iHiProd] == 0 && --iHiProd <= 2)
+                            goto ReturnResult;
+                    }
+                    else
+                    {
+                        // Signs the same, add.
+                        //
+                        low64 += tmp64;
+                        high += tmpHigh;
+
+                        // Propagate carry
+                        //
+                        if (low64 < tmp64)
+                        {
+                            high++;
+                            if (high > tmpHigh)
+                                goto NoCarry;
+                        }
+                        else if (high >= tmpHigh)
+                            goto NoCarry;
+
+                        uint* rgulNum = (uint*)&bufNum;
+                        for (uint iCur = 3; ++rgulNum[iCur++] == 0;)
+                        {
+                            Debug.Assert(iCur < bufNum.Length);
+                            if (iHiProd < iCur)
+                            {
+                                rgulNum[iCur] = 1;
+                                iHiProd = iCur;
+                                break;
+                            }
+                        }
+                    }
+NoCarry:
+
+                    bufNum.Low64 = low64;
+                    bufNum.U2 = high;
+                    int scale = ScaleResult(&bufNum, iHiProd, (byte)(flags >> ScaleShift));
+                    flags = (flags & ~ScaleMask) | ((uint)scale << ScaleShift);
+                    low64 = bufNum.Low64;
+                    high = bufNum.U2;
+                    goto ReturnResult;
+                }
+
+SignFlip:
+                {
+                    // Got negative result.  Flip its sign.
+                    flags ^= SignMask;
+                    high = ~high;
+                    low64 = (ulong)-(long)low64;
+                    if (low64 == 0)
+                        high++;
+                    goto ReturnResult;
+                }
+
+AlignedScale:
+                {
+                    // The addition carried above 96 bits.
+                    // Divide the value by 10, dropping the scale factor.
+                    //
+                    if ((flags & ScaleMask) == 0)
+                        throw new OverflowException(SR.Overflow_Decimal);
+                    flags -= 1 << ScaleShift;
+
+                    const uint den = 10;
+                    ulong num = high + (1UL << 32);
+                    high = (uint)(num / den);
+                    num = ((num - high * den) << 32) + (low64 >> 32);
+                    uint div = (uint)(num / den);
+                    num = ((num - div * den) << 32) + (uint)low64;
+                    low64 = div;
+                    low64 <<= 32;
+                    div = (uint)(num / den);
+                    low64 += div;
+                    div = (uint)num - div * den;
+
+                    // See if we need to round up.
+                    //
+                    if (div >= 5 && (div > 5 || (low64 & 1) != 0))
+                    {
+                        if (++low64 == 0)
+                            high++;
+                    }
+                    goto ReturnResult;
+                }
+
+AlignedAdd:
+                {
+                    ulong d1Low64 = low64;
+                    uint d1High = high;
+                    if (bSign)
+                    {
+                        // Signs differ - subtract
+                        //
+                        low64 = d1Low64 - d2.Low64;
+                        high = d1High - d2.High;
+
+                        // Propagate carry
+                        //
+                        if (low64 > d1Low64)
+                        {
+                            high--;
+                            if (high >= d1High)
+                                goto SignFlip;
+                        }
+                        else if (high > d1High)
+                            goto SignFlip;
+                    }
+                    else
+                    {
+                        // Signs are the same - add
+                        //
+                        low64 = d1Low64 + d2.Low64;
+                        high = d1High + d2.High;
+
+                        // Propagate carry
+                        //
+                        if (low64 < d1Low64)
+                        {
+                            high++;
+                            if (high <= d1High)
+                                goto AlignedScale;
+                        }
+                        else if (high < d1High)
+                            goto AlignedScale;
+                    }
+                    goto ReturnResult;
+                }
+
+ReturnResult:
+                d1.uflags = flags;
+                d1.High = high;
+                d1.Low64 = low64;
+                return;
+            }
+
+#endregion
+
+            //**********************************************************************
+            // VarCyFromDec - Convert Currency to Decimal (similar to OleAut32 api.)
+            //**********************************************************************
+            internal static long VarCyFromDec(ref DecCalc pdecIn)
+            {
+                long value;
+
+                int scale = pdecIn.Scale - 4;
+                // Need to scale to get 4 decimal places.  -4 <= scale <= 24.
+                //
+                if (scale < 0)
+                {
+                    if (pdecIn.High != 0)
+                        goto ThrowOverflow;
+                    uint pwr = s_powers10[-scale];
+                    ulong high = UInt32x32To64(pwr, pdecIn.Mid);
+                    if (high > uint.MaxValue)
+                        goto ThrowOverflow;
+                    ulong low = UInt32x32To64(pwr, pdecIn.Low);
+                    low += high <<= 32;
+                    if (low < high)
+                        goto ThrowOverflow;
+                    value = (long)low;
+                }
+                else
+                {
+                    if (scale != 0)
+                        InternalRound(ref pdecIn, (uint)scale, RoundingMode.ToEven);
+                    if (pdecIn.High != 0)
+                        goto ThrowOverflow;
+                    value = (long)pdecIn.Low64;
+                }
+
+                if (value < 0 && (value != long.MinValue || !pdecIn.IsNegative))
+                    goto ThrowOverflow;
+
+                if (pdecIn.IsNegative)
+                    value = -value;
+
+                return value;
+
+ThrowOverflow:
+                throw new OverflowException(SR.Overflow_Currency);
+            }
+
+            //**********************************************************************
+            // VarDecCmp - Decimal Compare updated to return values similar to ICompareTo
+            //**********************************************************************
+            internal static int VarDecCmp(in decimal pdecL, in decimal pdecR)
+            {
+                if ((pdecR.Low | pdecR.Mid | pdecR.High) == 0)
+                {
+                    if ((pdecL.Low | pdecL.Mid | pdecL.High) == 0)
+                        return 0;
+                    return (pdecL.flags >> 31) | 1;
+                }
+                if ((pdecL.Low | pdecL.Mid | pdecL.High) == 0)
+                    return -((pdecR.flags >> 31) | 1);
+
+                int sign = (pdecL.flags >> 31) - (pdecR.flags >> 31);
+                if (sign != 0)
+                    return sign;
+                return VarDecCmpSub(in pdecL, in pdecR);
+            }
+
+            private static int VarDecCmpSub(in decimal d1, in decimal d2)
+            {
+                int flags = d2.flags;
+                int sign = (flags >> 31) | 1;
+                int iScale = flags - d1.flags;
+
+                ulong low64 = d1.Low64;
+                uint high = d1.High;
+
+                ulong d2Low64 = d2.Low64;
+                uint d2High = d2.High;
+
+                if (iScale != 0)
+                {
+                    iScale >>= ScaleShift;
+
+                    // Scale factors are not equal. Assume that a larger scale factor (more decimal places) is likely to mean that number is smaller.
+                    // Start by guessing that the right operand has the larger scale factor.
+                    if (iScale < 0)
+                    {
+                        // Guessed scale factor wrong. Swap operands.
+                        iScale = -iScale;
+                        sign = -sign;
+
+                        ulong tmp64 = low64;
+                        low64 = d2Low64;
+                        d2Low64 = tmp64;
+
+                        uint tmp = high;
+                        high = d2High;
+                        d2High = tmp;
+                    }
+
+                    // d1 will need to be multiplied by 10^iScale so it will have the same scale as d2.
+                    // Scaling loop, up to 10^9 at a time.
+                    do
+                    {
+                        uint ulPwr = iScale >= MaxInt32Scale ? TenToPowerNine : s_powers10[iScale];
+                        ulong tmpLow = UInt32x32To64((uint)low64, ulPwr);
+                        ulong tmp = UInt32x32To64((uint)(low64 >> 32), ulPwr) + (tmpLow >> 32);
+                        low64 = (uint)tmpLow + (tmp << 32);
+                        tmp >>= 32;
+                        tmp += UInt32x32To64(high, ulPwr);
+                        // If the scaled value has more than 96 significant bits then it's greater than d2
+                        if (tmp > uint.MaxValue)
+                            return sign;
+                        high = (uint)tmp;
+                    } while ((iScale -= MaxInt32Scale) > 0);
+                }
+
+                uint cmpHigh = high - d2High;
+                if (cmpHigh != 0)
+                {
+                    // check for overflow
+                    if (cmpHigh > high)
+                        sign = -sign;
+                    return sign;
+                }
+
+                ulong cmpLow64 = low64 - d2Low64;
+                if (cmpLow64 == 0)
+                    sign = 0;
+                // check for overflow
+                else if (cmpLow64 > low64)
+                    sign = -sign;
+                return sign;
+            }
+
+            //**********************************************************************
+            // VarDecMul - Decimal Multiply
+            //**********************************************************************
+            internal static unsafe void VarDecMul(ref DecCalc pdecL, ref DecCalc pdecR)
+            {
+                int iScale = (byte)(pdecL.uflags + pdecR.uflags >> ScaleShift);
+
+                ulong tmp;
+                uint iHiProd;
+                Buf24 bufProd;
+                _ = &bufProd; // workaround for CS0165
+
+                if ((pdecL.High | pdecL.Mid) == 0)
+                {
+                    if ((pdecR.High | pdecR.Mid) == 0)
+                    {
+                        // Upper 64 bits are zero.
+                        //
+                        ulong low64 = UInt32x32To64(pdecL.Low, pdecR.Low);
+                        if (iScale > DEC_SCALE_MAX)
+                        {
+                            // Result iScale is too big.  Divide result by power of 10 to reduce it.
+                            // If the amount to divide by is > 19 the result is guaranteed
+                            // less than 1/2.  [max value in 64 bits = 1.84E19]
+                            //
+                            if (iScale > DEC_SCALE_MAX + MaxInt64Scale)
+                                goto ReturnZero;
+
+                            iScale -= DEC_SCALE_MAX + 1;
+                            ulong ulPwr = s_ulongPowers10[iScale];
+
+                            // TODO: https://github.com/dotnet/coreclr/issues/3439
+                            tmp = low64 / ulPwr;
+                            ulong remainder = low64 - tmp * ulPwr;
+                            low64 = tmp;
+
+                            // Round result.  See if remainder >= 1/2 of divisor.
+                            // Divisor is a power of 10, so it is always even.
+                            //
+                            ulPwr >>= 1;
+                            if (remainder >= ulPwr && (remainder > ulPwr || ((uint)low64 & 1) > 0))
+                                low64++;
+
+                            iScale = DEC_SCALE_MAX;
+                        }
+                        pdecL.Low64 = low64;
+                        pdecL.uflags = ((pdecR.uflags ^ pdecL.uflags) & SignMask) | ((uint)iScale << ScaleShift);
+                        return;
+                    }
+                    else
+                    {
+                        // Left value is 32-bit, result fits in 4 uints
+                        tmp = UInt32x32To64(pdecL.Low, pdecR.Low);
+                        bufProd.U0 = (uint)tmp;
+
+                        tmp = UInt32x32To64(pdecL.Low, pdecR.Mid) + (tmp >> 32);
+                        bufProd.U1 = (uint)tmp;
+                        tmp >>= 32;
+
+                        if (pdecR.High != 0)
+                        {
+                            tmp += UInt32x32To64(pdecL.Low, pdecR.High);
+                            if (tmp > uint.MaxValue)
+                            {
+                                bufProd.Mid64 = tmp;
+                                iHiProd = 3;
+                                goto SkipScan;
+                            }
+                        }
+                        if ((uint)tmp != 0)
+                        {
+                            bufProd.U2 = (uint)tmp;
+                            iHiProd = 2;
+                            goto SkipScan;
+                        }
+                        iHiProd = 1;
+                    }
+                }
+                else if ((pdecR.High | pdecR.Mid) == 0)
+                {
+                    // Right value is 32-bit, result fits in 4 uints
+                    tmp = UInt32x32To64(pdecR.Low, pdecL.Low);
+                    bufProd.U0 = (uint)tmp;
+
+                    tmp = UInt32x32To64(pdecR.Low, pdecL.Mid) + (tmp >> 32);
+                    bufProd.U1 = (uint)tmp;
+                    tmp >>= 32;
+
+                    if (pdecL.High != 0)
+                    {
+                        tmp += UInt32x32To64(pdecR.Low, pdecL.High);
+                        if (tmp > uint.MaxValue)
+                        {
+                            bufProd.Mid64 = tmp;
+                            iHiProd = 3;
+                            goto SkipScan;
+                        }
+                    }
+                    if ((uint)tmp != 0)
+                    {
+                        bufProd.U2 = (uint)tmp;
+                        iHiProd = 2;
+                        goto SkipScan;
+                    }
+                    iHiProd = 1;
+                }
+                else
+                {
+                    // Both operands have bits set in the upper 64 bits.
+                    //
+                    // Compute and accumulate the 9 partial products into a
+                    // 192-bit (24-byte) result.
+                    //
+                    //        [l-h][l-m][l-l]      left high, middle, low
+                    //         x    [r-h][r-m][r-l]      right high, middle, low
+                    // ------------------------------
+                    //
+                    //             [0-h][0-l]      l-l * r-l
+                    //        [1ah][1al]      l-l * r-m
+                    //        [1bh][1bl]      l-m * r-l
+                    //       [2ah][2al]          l-m * r-m
+                    //       [2bh][2bl]          l-l * r-h
+                    //       [2ch][2cl]          l-h * r-l
+                    //      [3ah][3al]          l-m * r-h
+                    //      [3bh][3bl]          l-h * r-m
+                    // [4-h][4-l]              l-h * r-h
+                    // ------------------------------
+                    // [p-5][p-4][p-3][p-2][p-1][p-0]      prod[] array
+                    //
+
+                    tmp = UInt32x32To64(pdecL.Low, pdecR.Low);
+                    bufProd.U0 = (uint)tmp;
+
+                    ulong tmp2 = UInt32x32To64(pdecL.Low, pdecR.Mid) + (tmp >> 32);
+
+                    tmp = UInt32x32To64(pdecL.Mid, pdecR.Low);
+                    tmp += tmp2; // this could generate carry
+                    bufProd.U1 = (uint)tmp;
+                    if (tmp < tmp2) // detect carry
+                        tmp2 = (tmp >> 32) | (1UL << 32);
+                    else
+                        tmp2 = tmp >> 32;
+
+                    tmp = UInt32x32To64(pdecL.Mid, pdecR.Mid) + tmp2;
+
+                    if ((pdecL.High | pdecR.High) > 0)
+                    {
+                        // Highest 32 bits is non-zero.     Calculate 5 more partial products.
+                        //
+                        tmp2 = UInt32x32To64(pdecL.Low, pdecR.High);
+                        tmp += tmp2; // this could generate carry
+                        uint tmp3 = 0;
+                        if (tmp < tmp2) // detect carry
+                            tmp3 = 1;
+
+                        tmp2 = UInt32x32To64(pdecL.High, pdecR.Low);
+                        tmp += tmp2; // this could generate carry
+                        bufProd.U2 = (uint)tmp;
+                        if (tmp < tmp2) // detect carry
+                            tmp3++;
+                        tmp2 = ((ulong)tmp3 << 32) | (tmp >> 32);
+
+                        tmp = UInt32x32To64(pdecL.Mid, pdecR.High);
+                        tmp += tmp2; // this could generate carry
+                        tmp3 = 0;
+                        if (tmp < tmp2) // detect carry
+                            tmp3 = 1;
+
+                        tmp2 = UInt32x32To64(pdecL.High, pdecR.Mid);
+                        tmp += tmp2; // this could generate carry
+                        bufProd.U3 = (uint)tmp;
+                        if (tmp < tmp2) // detect carry
+                            tmp3++;
+                        tmp = ((ulong)tmp3 << 32) | (tmp >> 32);
+
+                        bufProd.High64 = UInt32x32To64(pdecL.High, pdecR.High) + tmp;
+
+                        iHiProd = 5;
+                    }
+                    else if (tmp != 0)
+                    {
+                        bufProd.Mid64 = tmp;
+                        iHiProd = 3;
+                    }
+                    else
+                        iHiProd = 1;
+                }
+
+                // Check for leading zero ULONGs on the product
+                //
+                uint* rgulProd = (uint*)&bufProd;
+                while (rgulProd[(int)iHiProd] == 0)
+                {
+                    if (iHiProd == 0)
+                        goto ReturnZero;
+                    iHiProd--;
+                }
+
+SkipScan:
+                if (iHiProd > 2 || iScale > DEC_SCALE_MAX)
+                {
+                    iScale = ScaleResult(&bufProd, iHiProd, iScale);
+                }
+
+                pdecL.Low64 = bufProd.Low64;
+                pdecL.High = bufProd.U2;
+                pdecL.uflags = ((pdecR.uflags ^ pdecL.uflags) & SignMask) | ((uint)iScale << ScaleShift);
+                return;
+
+ReturnZero:
+                pdecL = default;
+            }
+
+            //**********************************************************************
+            // VarDecFromR4 - Convert float to Decimal
+            //**********************************************************************
+            internal static void VarDecFromR4(float input, out DecCalc pdecOut)
+            {
+                pdecOut = default;
+
+                // The most we can scale by is 10^28, which is just slightly more
+                // than 2^93.  So a float with an exponent of -94 could just
+                // barely reach 0.5, but smaller exponents will always round to zero.
+                //
+                const uint SNGBIAS = 126;
+                int iExp = (int)(GetExponent(input) - SNGBIAS);
+                if (iExp < -94)
+                    return; // result should be zeroed out
+
+                if (iExp > 96)
+                    throw new OverflowException(SR.Overflow_Decimal);
+
+                uint flags = 0;
+                if (input < 0)
+                {
+                    input = -input;
+                    flags = SignMask;
+                }
+
+                // Round the input to a 7-digit integer.  The R4 format has
+                // only 7 digits of precision, and we want to keep garbage digits
+                // out of the Decimal were making.
+                //
+                // Calculate max power of 10 input value could have by multiplying
+                // the exponent by log10(2).  Using scaled integer multiplcation,
+                // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
+                //
+                double dbl = input;
+                int iPower = 6 - ((iExp * 19728) >> 16);
+                // iPower is between -22 and 35
+
+                if (iPower >= 0)
+                {
+                    // We have less than 7 digits, scale input up.
+                    //
+                    if (iPower > DEC_SCALE_MAX)
+                        iPower = DEC_SCALE_MAX;
+
+                    dbl *= s_doublePowers10[iPower];
+                }
+                else
+                {
+                    if (iPower != -1 || dbl >= 1E7)
+                        dbl /= s_doublePowers10[-iPower];
+                    else
+                        iPower = 0; // didn't scale it
+                }
+
+                Debug.Assert(dbl < 1E7);
+                if (dbl < 1E6 && iPower < DEC_SCALE_MAX)
+                {
+                    dbl *= 10;
+                    iPower++;
+                    Debug.Assert(dbl >= 1E6);
+                }
+
+                // Round to integer
+                //
+                uint ulMant;
+                // with SSE4.1 support ROUNDSD can be used
+                if (X86.Sse41.IsSupported)
+                    ulMant = (uint)(int)Math.Round(dbl);
+                else
+                {
+                    ulMant = (uint)(int)dbl;
+                    dbl -= (int)ulMant;  // difference between input & integer
+                    if (dbl > 0.5 || dbl == 0.5 && (ulMant & 1) != 0)
+                        ulMant++;
+                }
+
+                if (ulMant == 0)
+                    return;  // result should be zeroed out
+
+                if (iPower < 0)
+                {
+                    // Add -iPower factors of 10, -iPower <= (29 - 7) = 22.
+                    //
+                    iPower = -iPower;
+                    if (iPower < 10)
+                    {
+                        pdecOut.Low64 = UInt32x32To64(ulMant, s_powers10[iPower]);
+                    }
+                    else
+                    {
+                        // Have a big power of 10.
+                        //
+                        if (iPower > 18)
+                        {
+                            ulong low64 = UInt32x32To64(ulMant, s_powers10[iPower - 18]);
+                            UInt64x64To128(low64, TenToPowerEighteen, ref pdecOut);
+                        }
+                        else
+                        {
+                            ulong low64 = UInt32x32To64(ulMant, s_powers10[iPower - 9]);
+                            ulong hi64 = UInt32x32To64(TenToPowerNine, (uint)(low64 >> 32));
+                            low64 = UInt32x32To64(TenToPowerNine, (uint)low64);
+                            pdecOut.Low = (uint)low64;
+                            hi64 += low64 >> 32;
+                            pdecOut.Mid = (uint)hi64;
+                            hi64 >>= 32;
+                            pdecOut.High = (uint)hi64;
+                        }
+                    }
+                }
+                else
+                {
+                    // Factor out powers of 10 to reduce the scale, if possible.
+                    // The maximum number we could factor out would be 6.  This
+                    // comes from the fact we have a 7-digit number, and the
+                    // MSD must be non-zero -- but the lower 6 digits could be
+                    // zero.  Note also the scale factor is never negative, so
+                    // we can't scale by any more than the power we used to
+                    // get the integer.
+                    //
+                    int lmax = iPower;
+                    if (lmax > 6)
+                        lmax = 6;
+
+                    if ((ulMant & 0xF) == 0 && lmax >= 4)
+                    {
+                        const uint den = 10000;
+                        uint div = ulMant / den;
+                        if (ulMant == div * den)
+                        {
+                            ulMant = div;
+                            iPower -= 4;
+                            lmax -= 4;
+                        }
+                    }
+
+                    if ((ulMant & 3) == 0 && lmax >= 2)
+                    {
+                        const uint den = 100;
+                        uint div = ulMant / den;
+                        if (ulMant == div * den)
+                        {
+                            ulMant = div;
+                            iPower -= 2;
+                            lmax -= 2;
+                        }
+                    }
+
+                    if ((ulMant & 1) == 0 && lmax >= 1)
+                    {
+                        const uint den = 10;
+                        uint div = ulMant / den;
+                        if (ulMant == div * den)
+                        {
+                            ulMant = div;
+                            iPower--;
+                        }
+                    }
+
+                    flags |= (uint)iPower << ScaleShift;
+                    pdecOut.Low = ulMant;
+                }
+
+                pdecOut.uflags = flags;
+            }
+
+            //**********************************************************************
+            // VarDecFromR8 - Convert double to Decimal
+            //**********************************************************************
+            internal static void VarDecFromR8(double input, out DecCalc pdecOut)
+            {
+                pdecOut = default;
+
+                // The most we can scale by is 10^28, which is just slightly more
+                // than 2^93.  So a float with an exponent of -94 could just
+                // barely reach 0.5, but smaller exponents will always round to zero.
+                //
+                const uint DBLBIAS = 1022;
+                int iExp = (int)(GetExponent(input) - DBLBIAS);
+                if (iExp < -94)
+                    return; // result should be zeroed out
+
+                if (iExp > 96)
+                    throw new OverflowException(SR.Overflow_Decimal);
+
+                uint flags = 0;
+                if (input < 0)
+                {
+                    input = -input;
+                    flags = SignMask;
+                }
+
+                // Round the input to a 15-digit integer.  The R8 format has
+                // only 15 digits of precision, and we want to keep garbage digits
+                // out of the Decimal were making.
+                //
+                // Calculate max power of 10 input value could have by multiplying
+                // the exponent by log10(2).  Using scaled integer multiplcation,
+                // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
+                //
+                double dbl = input;
+                int iPower = 14 - ((iExp * 19728) >> 16);
+                // iPower is between -14 and 43
+
+                if (iPower >= 0)
+                {
+                    // We have less than 15 digits, scale input up.
+                    //
+                    if (iPower > DEC_SCALE_MAX)
+                        iPower = DEC_SCALE_MAX;
+
+                    dbl *= s_doublePowers10[iPower];
+                }
+                else
+                {
+                    if (iPower != -1 || dbl >= 1E15)
+                        dbl /= s_doublePowers10[-iPower];
+                    else
+                        iPower = 0; // didn't scale it
+                }
+
+                Debug.Assert(dbl < 1E15);
+                if (dbl < 1E14 && iPower < DEC_SCALE_MAX)
+                {
+                    dbl *= 10;
+                    iPower++;
+                    Debug.Assert(dbl >= 1E14);
+                }
+
+                // Round to int64
+                //
+                ulong ulMant;
+                // with SSE4.1 support ROUNDSD can be used
+                if (X86.Sse41.IsSupported)
+                    ulMant = (ulong)(long)Math.Round(dbl);
+                else
+                {
+                    ulMant = (ulong)(long)dbl;
+                    dbl -= (long)ulMant;  // difference between input & integer
+                    if (dbl > 0.5 || dbl == 0.5 && (ulMant & 1) != 0)
+                        ulMant++;
+                }
+
+                if (ulMant == 0)
+                    return;  // result should be zeroed out
+
+                if (iPower < 0)
+                {
+                    // Add -iPower factors of 10, -iPower <= (29 - 15) = 14.
+                    //
+                    iPower = -iPower;
+                    if (iPower < 10)
+                    {
+                        var pow10 = s_powers10[iPower];
+                        ulong low64 = UInt32x32To64((uint)ulMant, pow10);
+                        ulong hi64 = UInt32x32To64((uint)(ulMant >> 32), pow10);
+                        pdecOut.Low = (uint)low64;
+                        hi64 += low64 >> 32;
+                        pdecOut.Mid = (uint)hi64;
+                        hi64 >>= 32;
+                        pdecOut.High = (uint)hi64;
+                    }
+                    else
+                    {
+                        // Have a big power of 10.
+                        //
+                        Debug.Assert(iPower <= 14);
+                        UInt64x64To128(ulMant, s_ulongPowers10[iPower - 1], ref pdecOut);
+                    }
+                }
+                else
+                {
+                    // Factor out powers of 10 to reduce the scale, if possible.
+                    // The maximum number we could factor out would be 14.  This
+                    // comes from the fact we have a 15-digit number, and the
+                    // MSD must be non-zero -- but the lower 14 digits could be
+                    // zero.  Note also the scale factor is never negative, so
+                    // we can't scale by any more than the power we used to
+                    // get the integer.
+                    //
+                    int lmax = iPower;
+                    if (lmax > 14)
+                        lmax = 14;
+
+                    if ((byte)ulMant == 0 && lmax >= 8)
+                    {
+                        const uint den = 100000000;
+                        ulong div = ulMant / den;
+                        if ((uint)ulMant == (uint)(div * den))
+                        {
+                            ulMant = div;
+                            iPower -= 8;
+                            lmax -= 8;
+                        }
+                    }
+
+                    if (((uint)ulMant & 0xF) == 0 && lmax >= 4)
+                    {
+                        const uint den = 10000;
+                        ulong div = ulMant / den;
+                        if ((uint)ulMant == (uint)(div * den))
+                        {
+                            ulMant = div;
+                            iPower -= 4;
+                            lmax -= 4;
+                        }
+                    }
+
+                    if (((uint)ulMant & 3) == 0 && lmax >= 2)
+                    {
+                        const uint den = 100;
+                        ulong div = ulMant / den;
+                        if ((uint)ulMant == (uint)(div * den))
+                        {
+                            ulMant = div;
+                            iPower -= 2;
+                            lmax -= 2;
+                        }
+                    }
+
+                    if (((uint)ulMant & 1) == 0 && lmax >= 1)
+                    {
+                        const uint den = 10;
+                        ulong div = ulMant / den;
+                        if ((uint)ulMant == (uint)(div * den))
+                        {
+                            ulMant = div;
+                            iPower--;
+                        }
+                    }
+
+                    flags |= (uint)iPower << ScaleShift;
+                    pdecOut.Low64 = ulMant;
+                }
+
+                pdecOut.uflags = flags;
+            }
+
+            //**********************************************************************
+            // VarR4ToDec - Convert Decimal to float
+            //**********************************************************************
+            internal static float VarR4FromDec(ref decimal pdecIn)
+            {
+                return (float)VarR8FromDec(ref pdecIn);
+            }
+
+            //**********************************************************************
+            // VarR8ToDec - Convert Decimal to double
+            //**********************************************************************
+            internal static double VarR8FromDec(ref decimal pdecIn)
+            {
+                // Value taken via reverse engineering the double that corresponds to 2^64. (oleaut32 has ds2to64 = DEFDS(0, 0, DBLBIAS + 65, 0))
+                const double ds2to64 = 1.8446744073709552e+019;
+
+                double dbl = ((double)pdecIn.Low64 +
+                    (double)pdecIn.High * ds2to64) / s_doublePowers10[pdecIn.Scale];
+
+                if (pdecIn.IsNegative)
+                    dbl = -dbl;
+
+                return dbl;
+            }
+
+            internal static int GetHashCode(in decimal d)
+            {
+                if ((d.Low | d.Mid | d.High) == 0)
+                    return 0;
+
+                uint flags = (uint)d.flags;
+                if ((flags & ScaleMask) == 0 || (d.Low & 1) != 0)
+                    return (int)(flags ^ d.High ^ d.Mid ^ d.Low);
+
+                int scale = (byte)(flags >> ScaleShift);
+                uint low = d.Low;
+                ulong high64 = ((ulong)d.High << 32) | d.Mid;
+
+                Unscale(ref low, ref high64, ref scale);
+
+                flags = ((flags) & ~ScaleMask) | (uint)scale << ScaleShift;
+                return (int)(flags ^ (uint)(high64 >> 32) ^ (uint)high64 ^ low);
+            }
+
+            // VarDecDiv divides two decimal values.  On return, d1 contains the result
+            // of the operation.
+            internal static unsafe void VarDecDiv(ref DecCalc d1, ref DecCalc d2)
+            {
+                Buf12 bufQuo, bufDivisor;
+                _ = &bufQuo; // workaround for CS0165
+                _ = &bufDivisor; // workaround for CS0165
+                uint ulPwr;
+                int iCurScale;
+
+                int iScale = (sbyte)(d1.uflags - d2.uflags >> ScaleShift);
+                bool fUnscale = false;
+                uint ulTmp;
+
+                if (d2.High == 0 && d2.Mid == 0)
+                {
+                    // Divisor is only 32 bits.  Easy divide.
+                    //
+                    uint den = d2.Low;
+                    if (den == 0)
+                        throw new DivideByZeroException();
+
+                    bufQuo.Low64 = d1.Low64;
+                    bufQuo.U2 = d1.High;
+                    uint remainder = Div96By32(ref bufQuo, den);
+
+                    for (;;)
+                    {
+                        if (remainder == 0)
+                        {
+                            if (iScale < 0)
+                            {
+                                iCurScale = Math.Min(9, -iScale);
+                                goto HaveScale;
+                            }
+                            break;
+                        }
+
+                        // We need to unscale if and only if we have a non-zero remainder
+                        fUnscale = true;
+
+                        // We have computed a quotient based on the natural scale
+                        // ( <dividend scale> - <divisor scale> ).  We have a non-zero
+                        // remainder, so now we should increase the scale if possible to
+                        // include more quotient bits.
+                        //
+                        // If it doesn't cause overflow, we'll loop scaling by 10^9 and
+                        // computing more quotient bits as long as the remainder stays
+                        // non-zero.  If scaling by that much would cause overflow, we'll
+                        // drop out of the loop and scale by as much as we can.
+                        //
+                        // Scaling by 10^9 will overflow if rgulQuo[2].rgulQuo[1] >= 2^32 / 10^9
+                        // = 4.294 967 296.  So the upper limit is rgulQuo[2] == 4 and
+                        // rgulQuo[1] == 0.294 967 296 * 2^32 = 1,266,874,889.7+.  Since
+                        // quotient bits in rgulQuo[0] could be all 1's, then 1,266,874,888
+                        // is the largest value in rgulQuo[1] (when rgulQuo[2] == 4) that is
+                        // assured not to overflow.
+                        //
+                        if (iScale == DEC_SCALE_MAX || (iCurScale = SearchScale(ref bufQuo, iScale)) == 0)
+                        {
+                            // No more scaling to be done, but remainder is non-zero.
+                            // Round quotient.
+                            //
+                            ulTmp = remainder << 1;
+                            if (ulTmp < remainder || ulTmp >= den && (ulTmp > den || (bufQuo.U0 & 1) != 0))
+                                goto RoundUp;
+                            break;
+                        }
+
+                        HaveScale:
+                        ulPwr = s_powers10[iCurScale];
+                        iScale += iCurScale;
+
+                        if (IncreaseScale(ref bufQuo, ulPwr) != 0)
+                            goto ThrowOverflow;
+
+                        ulong num = UInt32x32To64(remainder, ulPwr);
+                        // TODO: https://github.com/dotnet/coreclr/issues/3439
+                        uint div = (uint)(num / den);
+                        remainder = (uint)num - div * den;
+
+                        if (!Add32To96(ref bufQuo, div))
+                        {
+                            iScale = OverflowUnscale(ref bufQuo, iScale, remainder != 0);
+                            break;
+                        }
+                    } // for (;;)
+                }
+                else
+                {
+                    // Divisor has bits set in the upper 64 bits.
+                    //
+                    // Divisor must be fully normalized (shifted so bit 31 of the most
+                    // significant ULONG is 1).  Locate the MSB so we know how much to
+                    // normalize by.  The dividend will be shifted by the same amount so
+                    // the quotient is not changed.
+                    //
+                    bufDivisor.Low64 = d2.Low64;
+                    ulTmp = d2.High;
+                    bufDivisor.U2 = ulTmp;
+                    if (ulTmp == 0)
+                        ulTmp = d2.Mid;
+
+                    iCurScale = X86.Lzcnt.IsSupported ? (int)X86.Lzcnt.LeadingZeroCount(ulTmp) : LeadingZeroCount(ulTmp);
+
+                    // Shift both dividend and divisor left by iCurScale.
+                    //
+                    Buf16 bufRem;
+                    _ = &bufRem; // workaround for CS0165
+                    bufRem.Low64 = d1.Low64 << iCurScale;
+                    bufRem.High64 = (d1.Mid + ((ulong)d1.High << 32)) >> (31 - iCurScale) >> 1;
+
+                    ulong divisor = bufDivisor.Low64 << iCurScale;
+
+                    if (bufDivisor.U2 == 0)
+                    {
+                        // Have a 64-bit divisor in sdlDivisor.  The remainder
+                        // (currently 96 bits spread over 4 ULONGs) will be < divisor.
+                        //
+
+                        bufQuo.U1 = Div96By64(ref *(Buf12*)&bufRem.U1, divisor);
+                        bufQuo.U0 = Div96By64(ref *(Buf12*)&bufRem, divisor);
+
+                        for (;;)
+                        {
+                            if (bufRem.Low64 == 0)
+                            {
+                                if (iScale < 0)
+                                {
+                                    iCurScale = Math.Min(9, -iScale);
+                                    goto HaveScale64;
+                                }
+                                break;
+                            }
+
+                            // We need to unscale if and only if we have a non-zero remainder
+                            fUnscale = true;
+
+                            // Remainder is non-zero.  Scale up quotient and remainder by
+                            // powers of 10 so we can compute more significant bits.
+                            //
+                            if (iScale == DEC_SCALE_MAX || (iCurScale = SearchScale(ref bufQuo, iScale)) == 0)
+                            {
+                                // No more scaling to be done, but remainder is non-zero.
+                                // Round quotient.
+                                //
+                                ulong tmp = bufRem.Low64;
+                                if ((long)tmp < 0 || (tmp <<= 1) > divisor ||
+                                  (tmp == divisor && (bufQuo.U0 & 1) != 0))
+                                    goto RoundUp;
+                                break;
+                            }
+
+                            HaveScale64:
+                            ulPwr = s_powers10[iCurScale];
+                            iScale += iCurScale;
+
+                            if (IncreaseScale(ref bufQuo, ulPwr) != 0)
+                                goto ThrowOverflow;
+
+                            IncreaseScale64(ref *(Buf12*)&bufRem, ulPwr);
+                            ulTmp = Div96By64(ref *(Buf12*)&bufRem, divisor);
+                            if (!Add32To96(ref bufQuo, ulTmp))
+                            {
+                                iScale = OverflowUnscale(ref bufQuo, iScale, bufRem.Low64 != 0);
+                                break;
+                            }
+                        } // for (;;)
+                    }
+                    else
+                    {
+                        // Have a 96-bit divisor in rgulDivisor[].
+                        //
+                        // Start by finishing the shift left by iCurScale.
+                        //
+                        uint tmp = (uint)(bufDivisor.High64 >> (31 - iCurScale) >> 1);
+                        bufDivisor.Low64 = divisor;
+                        bufDivisor.U2 = tmp;
+
+                        // The remainder (currently 96 bits spread over 4 ULONGs)
+                        // will be < divisor.
+                        //
+                        bufQuo.Low64 = Div128By96(ref bufRem, ref bufDivisor);
+
+                        for (;;)
+                        {
+                            if ((bufRem.Low64 | bufRem.U2) == 0)
+                            {
+                                if (iScale < 0)
+                                {
+                                    iCurScale = Math.Min(9, -iScale);
+                                    goto HaveScale96;
+                                }
+                                break;
+                            }
+
+                            // We need to unscale if and only if we have a non-zero remainder
+                            fUnscale = true;
+
+                            // Remainder is non-zero.  Scale up quotient and remainder by
+                            // powers of 10 so we can compute more significant bits.
+                            //
+                            if (iScale == DEC_SCALE_MAX || (iCurScale = SearchScale(ref bufQuo, iScale)) == 0)
+                            {
+                                // No more scaling to be done, but remainder is non-zero.
+                                // Round quotient.
+                                //
+                                if ((int)bufRem.U2 < 0)
+                                {
+                                    goto RoundUp;
+                                }
+
+                                ulTmp = bufRem.U1 >> 31;
+                                bufRem.Low64 <<= 1;
+                                bufRem.U2 = (bufRem.U2 << 1) + ulTmp;
+
+                                if (bufRem.U2 > bufDivisor.U2 || bufRem.U2 == bufDivisor.U2 &&
+                                  (bufRem.Low64 > bufDivisor.Low64 || bufRem.Low64 == bufDivisor.Low64 &&
+                                  (bufQuo.U0 & 1) != 0))
+                                    goto RoundUp;
+                                break;
+                            }
+
+                            HaveScale96:
+                            ulPwr = s_powers10[iCurScale];
+                            iScale += iCurScale;
+
+                            if (IncreaseScale(ref bufQuo, ulPwr) != 0)
+                                goto ThrowOverflow;
+
+                            bufRem.U3 = IncreaseScale(ref *(Buf12*)&bufRem, ulPwr);
+                            ulTmp = Div128By96(ref bufRem, ref bufDivisor);
+                            if (!Add32To96(ref bufQuo, ulTmp))
+                            {
+                                iScale = OverflowUnscale(ref bufQuo, iScale, (bufRem.Low64 | bufRem.High64) != 0);
+                                break;
+                            }
+                        } // for (;;)
+                    }
+                }
+
+Unscale:
+                if (fUnscale)
+                {
+                    uint low = bufQuo.U0;
+                    ulong high64 = bufQuo.High64;
+                    Unscale(ref low, ref high64, ref iScale);
+                    d1.Low = low;
+                    d1.Mid = (uint)high64;
+                    d1.High = (uint)(high64 >> 32);
+                }
+                else
+                {
+                    d1.Low64 = bufQuo.Low64;
+                    d1.High = bufQuo.U2;
+                }
+
+                d1.uflags = ((d1.uflags ^ d2.uflags) & SignMask) | ((uint)iScale << ScaleShift);
+                return;
+
+RoundUp:
+                {
+                    if (++bufQuo.Low64 == 0 && ++bufQuo.U2 == 0)
+                    {
+                        iScale = OverflowUnscale(ref bufQuo, iScale, true);
+                    }
+                    goto Unscale;
+                }
+
+ThrowOverflow:
+                throw new OverflowException(SR.Overflow_Decimal);
+            }
+
+            //**********************************************************************
+            // VarDecMod - Computes the remainder between two decimals
+            //**********************************************************************
+            internal static void VarDecMod(ref DecCalc d1, ref DecCalc d2)
+            {
+                if ((d2.ulo | d2.umid | d2.uhi) == 0)
+                    throw new DivideByZeroException();
+
+                if ((d1.ulo | d1.umid | d1.uhi) == 0)
+                    return;
+
+                // In the operation x % y the sign of y does not matter. Result will have the sign of x.
+                d2.uflags = (d2.uflags & ~SignMask) | (d1.uflags & SignMask);
+
+                int cmp = VarDecCmpSub(in Unsafe.As<DecCalc, decimal>(ref d1), in Unsafe.As<DecCalc, decimal>(ref d2));
+                if (cmp == 0)
+                {
+                    d1.ulo = 0;
+                    d1.umid = 0;
+                    d1.uhi = 0;
+                    if (d2.uflags > d1.uflags)
+                        d1.uflags = d2.uflags;
+                    return;
+                }
+                if ((cmp ^ (int)(d1.uflags & SignMask)) < 0)
+                    return;
+
+                // This piece of code is to work around the fact that Dividing a decimal with 28 digits number by decimal which causes
+                // causes the result to be 28 digits, can cause to be incorrectly rounded up.
+                // eg. Decimal.MaxValue / 2 * Decimal.MaxValue will overflow since the division by 2 was rounded instead of being truncked.
+                DecCalc tmp = d2;
+                DecAddSub(ref d1, ref tmp, true);
+
+                // Formula:  d1 - (RoundTowardsZero(d1 / d2) * d2)
+                tmp = d1;
+                VarDecDiv(ref tmp, ref d2);
+                Truncate(ref Unsafe.As<DecCalc, decimal>(ref tmp));
+                VarDecMul(ref tmp, ref d2);
+                uint flags = d1.uflags;
+                DecAddSub(ref d1, ref tmp, true);
+                // See if the result has crossed 0
+                if (((flags ^ d1.uflags) & SignMask) != 0)
+                {
+                    if ((d1.Low | d1.Mid | d1.High) == 0 || d1.Scale == DEC_SCALE_MAX && d1.Low64 == 1 && d1.High == 0)
+                    {
+                        // Certain Remainder operations on decimals with 28 significant digits round
+                        // to [+-]0.0000000000000000000000000001m instead of [+-]0m during the intermediate calculations.
+                        // 'zero' results just need their sign corrected.
+                        d1.uflags ^= SignMask;
+                    }
+                    else
+                    {
+                        // If the division rounds up because it runs out of digits, the multiplied result can end up with a larger
+                        // absolute value and the result of the formula crosses 0. To correct it can add the divisor back.
+                        DecAddSub(ref d1, ref d2, false);
+                    }
+                }
+            }
+
+            internal enum RoundingMode
+            {
+                ToEven = 0,
+                AwayFromZero = 1,
+                Truncate = 2,
+                Floor = 3,
+                Ceiling = 4,
+            }
+
+            // Does an in-place round by the specified scale
+            internal static void InternalRound(ref DecCalc d, uint scale, RoundingMode mode)
+            {
+                // the scale becomes the desired decimal count
+                d.uflags -= scale << ScaleShift;
+
+                uint remainder, sticky = 0, power;
+                // First divide the value by constant 10^9 up to three times
+                while (scale >= MaxInt32Scale)
+                {
+                    scale -= MaxInt32Scale;
+
+                    const uint divisor = TenToPowerNine;
+                    uint n = d.uhi;
+                    if (n == 0)
+                    {
+                        ulong tmp = d.Low64;
+                        ulong div = tmp / divisor;
+                        d.Low64 = div;
+                        remainder = (uint)(tmp - div * divisor);
+                    }
+                    else
+                    {
+                        uint q;
+                        d.uhi = q = n / divisor;
+                        remainder = n - q * divisor;
+                        n = d.umid;
+                        if ((n | remainder) != 0)
+                        {
+                            d.umid = q = (uint)((((ulong)remainder << 32) | n) / divisor);
+                            remainder = n - q * divisor;
+                        }
+                        n = d.ulo;
+                        if ((n | remainder) != 0)
+                        {
+                            d.ulo = q = (uint)((((ulong)remainder << 32) | n) / divisor);
+                            remainder = n - q * divisor;
+                        }
+                    }
+                    power = divisor;
+                    if (scale == 0)
+                        goto checkRemainder;
+                    sticky |= remainder;
+                }
+
+                {
+                    power = s_powers10[scale];
+                    // TODO: https://github.com/dotnet/coreclr/issues/3439
+                    uint n = d.uhi;
+                    if (n == 0)
+                    {
+                        ulong tmp = d.Low64;
+                        if (tmp == 0)
+                        {
+                            if (mode <= RoundingMode.Truncate)
+                                goto done;
+                            remainder = 0;
+                            goto checkRemainder;
+                        }
+                        ulong div = tmp / power;
+                        d.Low64 = div;
+                        remainder = (uint)(tmp - div * power);
+                    }
+                    else
+                    {
+                        uint q;
+                        d.uhi = q = n / power;
+                        remainder = n - q * power;
+                        n = d.umid;
+                        if ((n | remainder) != 0)
+                        {
+                            d.umid = q = (uint)((((ulong)remainder << 32) | n) / power);
+                            remainder = n - q * power;
+                        }
+                        n = d.ulo;
+                        if ((n | remainder) != 0)
+                        {
+                            d.ulo = q = (uint)((((ulong)remainder << 32) | n) / power);
+                            remainder = n - q * power;
+                        }
+                    }
+                }
+
+checkRemainder:
+                if (mode == RoundingMode.Truncate)
+                    goto done;
+                else if (mode == RoundingMode.ToEven)
+                {
+                    // To do IEEE rounding, we add LSB of result to sticky bits so either causes round up if remainder * 2 == last divisor.
+                    remainder <<= 1;
+                    if ((sticky | d.ulo & 1) != 0)
+                        remainder++;
+                    if (power >= remainder)
+                        goto done;
+                }
+                else if (mode == RoundingMode.AwayFromZero)
+                {
+                    // Round away from zero at the mid point.
+                    remainder <<= 1;
+                    if (power > remainder)
+                        goto done;
+                }
+                else if (mode == RoundingMode.Floor)
+                {
+                    // Round toward -infinity if we have chopped off a non-zero amount from a negative value.
+                    if ((remainder | sticky) == 0 || !d.IsNegative)
+                        goto done;
+                }
+                else
+                {
+                    Debug.Assert(mode == RoundingMode.Ceiling);
+                    // Round toward infinity if we have chopped off a non-zero amount from a positive value.
+                    if ((remainder | sticky) == 0 || d.IsNegative)
+                        goto done;
+                }
+                if (++d.Low64 == 0)
+                    d.uhi++;
+done:
+                return;
+            }
+
+#region Number Formatting helpers
+
+            internal static uint DecDivMod1E9(ref DecCalc value)
+            {
+                ulong high64 = ((ulong)value.uhi << 32) + value.umid;
+                ulong div64 = high64 / TenToPowerNine;
+                value.uhi = (uint)(div64 >> 32);
+                value.umid = (uint)div64;
+
+                ulong num = ((high64 - (uint)div64 * TenToPowerNine) << 32) + value.ulo;
+                uint div = (uint)(num / TenToPowerNine);
+                value.ulo = div;
+                return (uint)num - div * TenToPowerNine;
+            }
+
+            internal static void DecAddInt32(ref DecCalc value, uint i)
+            {
+                if (D32AddCarry(ref value.ulo, i))
+                {
+                    if (D32AddCarry(ref value.umid, 1))
+                        D32AddCarry(ref value.uhi, 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 DecCalc value)
+            {
+                DecCalc d = value;
+                DecShiftLeft(ref value);
+                DecShiftLeft(ref value);
+                DecAdd(ref value, d);
+                DecShiftLeft(ref value);
+            }
+
+            private static void DecShiftLeft(ref DecCalc 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 DecCalc value, DecCalc d)
+            {
+                if (D32AddCarry(ref value.ulo, d.Low))
+                {
+                    if (D32AddCarry(ref value.umid, 1))
+                        D32AddCarry(ref value.uhi, 1);
+                }
+
+                if (D32AddCarry(ref value.umid, d.Mid))
+                    D32AddCarry(ref value.uhi, 1);
+
+                D32AddCarry(ref value.uhi, d.High);
+            }
+
+#endregion
+
+            struct PowerOvfl
+            {
+                public readonly uint Hi;
+                public readonly ulong MidLo;
+
+                public PowerOvfl(uint hi, uint mid, uint lo)
+                {
+                    Hi = hi;
+                    MidLo = ((ulong)mid << 32) + lo;
+                }
+            }
+
+            static readonly PowerOvfl[] PowerOvflValues = new[]
+            {
+                // This is a table of the largest values that can be in the upper two
+                // ULONGs of a 96-bit number that will not overflow when multiplied
+                // by a given power.  For the upper word, this is a table of
+                // 2^32 / 10^n for 1 <= n <= 8.  For the lower word, this is the
+                // remaining fraction part * 2^32.  2^32 = 4294967296.
+                //
+                new PowerOvfl(429496729, 2576980377, 2576980377),  // 10^1 remainder 0.6
+                new PowerOvfl(42949672,  4123168604, 687194767),   // 10^2 remainder 0.16
+                new PowerOvfl(4294967,   1271310319, 2645699854),  // 10^3 remainder 0.616
+                new PowerOvfl(429496,    3133608139, 694066715),   // 10^4 remainder 0.1616
+                new PowerOvfl(42949,     2890341191, 2216890319),  // 10^5 remainder 0.51616
+                new PowerOvfl(4294,      4154504685, 2369172679),  // 10^6 remainder 0.551616
+                new PowerOvfl(429,       2133437386, 4102387834),  // 10^7 remainder 0.9551616
+                new PowerOvfl(42,        4078814305, 410238783),   // 10^8 remainder 0.09991616
+            };
+
+            [StructLayout(LayoutKind.Explicit)]
+            private struct Buf12
+            {
+                [FieldOffset(0 * 4)]
+                public uint U0;
+                [FieldOffset(1 * 4)]
+                public uint U1;
+                [FieldOffset(2 * 4)]
+                public uint U2;
+
+                [FieldOffset(0)]
+                private ulong ulo64LE;
+                [FieldOffset(4)]
+                private ulong uhigh64LE;
+
+                public ulong Low64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U1 << 32) | U0;
+                    set { U1 = (uint)(value >> 32); U0 = (uint)value; }
+#else
+                    get => ulo64LE;
+                    set => ulo64LE = value;
+#endif
+                }
+
+                /// <summary>
+                /// U1-U2 combined (overlaps with Low64)
+                /// </summary>
+                public ulong High64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U2 << 32) | U1;
+                    set { U2 = (uint)(value >> 32); U1 = (uint)value; }
+#else
+                    get => uhigh64LE;
+                    set => uhigh64LE = value;
+#endif
+                }
+            }
+
+            [StructLayout(LayoutKind.Explicit)]
+            private struct Buf16
+            {
+                [FieldOffset(0 * 4)]
+                public uint U0;
+                [FieldOffset(1 * 4)]
+                public uint U1;
+                [FieldOffset(2 * 4)]
+                public uint U2;
+                [FieldOffset(3 * 4)]
+                public uint U3;
+
+                [FieldOffset(0 * 8)]
+                private ulong ulo64LE;
+                [FieldOffset(1 * 8)]
+                private ulong uhigh64LE;
+
+                public ulong Low64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U1 << 32) | U0;
+                    set { U1 = (uint)(value >> 32); U0 = (uint)value; }
+#else
+                    get => ulo64LE;
+                    set => ulo64LE = value;
+#endif
+                }
+
+                public ulong High64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U3 << 32) | U2;
+                    set { U3 = (uint)(value >> 32); U2 = (uint)value; }
+#else
+                    get => uhigh64LE;
+                    set => uhigh64LE = value;
+#endif
+                }
+            }
+
+            [StructLayout(LayoutKind.Explicit)]
+            private struct Buf24
+            {
+                [FieldOffset(0 * 4)]
+                public uint U0;
+                [FieldOffset(1 * 4)]
+                public uint U1;
+                [FieldOffset(2 * 4)]
+                public uint U2;
+                [FieldOffset(3 * 4)]
+                public uint U3;
+                [FieldOffset(4 * 4)]
+                public uint U4;
+                [FieldOffset(5 * 4)]
+                public uint U5;
+
+                [FieldOffset(0 * 8)]
+                private ulong ulo64LE;
+                [FieldOffset(1 * 8)]
+                private ulong umid64LE;
+                [FieldOffset(2 * 8)]
+                private ulong uhigh64LE;
+
+                public ulong Low64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U1 << 32) | U0;
+                    set { U1 = (uint)(value >> 32); U0 = (uint)value; }
+#else
+                    get => ulo64LE;
+                    set => ulo64LE = value;
+#endif
+                }
+
+                public ulong Mid64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U3 << 32) | U2;
+                    set { U3 = (uint)(value >> 32); U2 = (uint)value; }
+#else
+                    get => umid64LE;
+                    set => umid64LE = value;
+#endif
+                }
+
+                public ulong High64
+                {
+#if BIGENDIAN
+                    get => ((ulong)U5 << 32) | U4;
+                    set { U5 = (uint)(value >> 32); U4 = (uint)value; }
+#else
+                    get => uhigh64LE;
+                    set => uhigh64LE = value;
+#endif
+                }
+
+                public int Length => 6;
+            }
+        }
+    }
+}
@@ -2,15 +2,11 @@
 // 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;
+using System.Diagnostics;
 using System.Globalization;
-using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.Versioning;
+using System.Runtime.InteropServices;
 using System.Runtime.Serialization;
-using System.Diagnostics;
 
 namespace System
 {
@@ -60,7 +56,7 @@ namespace System
     [Serializable]
     [System.Runtime.Versioning.NonVersionable] // This only applies to field layout
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public partial struct Decimal : IFormattable, IComparable, IConvertible, IComparable<decimal>, IEquatable<decimal>, IDeserializationCallback, ISpanFormattable
+    public readonly partial struct Decimal : IFormattable, IComparable, IConvertible, IComparable<decimal>, IEquatable<decimal>, IDeserializationCallback, ISpanFormattable
     {
         // Sign mask for the flags field. A value of zero in this bit indicates a
         // positive Decimal value, and a value of one in this bit indicates a
@@ -69,8 +65,6 @@ namespace System
         // Look at OleAut's DECIMAL_NEG constant to check for negative values
         // in native code.
         private const int SignMask = unchecked((int)0x80000000);
-        private const byte DECIMAL_NEG = 0x80;
-        private const byte DECIMAL_ADD = 0x00;
 
         // Scale mask for the flags field. This byte in the flags field contains
         // the power of 10 to divide the Decimal value by. The scale byte must
@@ -80,23 +74,6 @@ namespace System
         // Number of bits scale is shifted by.
         private const int ScaleShift = 16;
 
-        // The maximum power of 10 that a 32 bit integer can store
-        private const int MaxInt32Scale = 9;
-
-        // Fast access for 10^n where n is 0-9        
-        private static uint[] Powers10 = new uint[] {
-            1,
-            10,
-            100,
-            1000,
-            10000,
-            100000,
-            1000000,
-            10000000,
-            100000000,
-            1000000000
-        };
-
         // Constant representing the Decimal value 0.
         public const decimal Zero = 0m;
 
@@ -114,15 +91,6 @@ namespace System
         // this constant is -79,228,162,514,264,337,593,543,950,335.
         public const decimal MinValue = -79228162514264337593543950335m;
 
-
-        // Constant representing the negative number that is the closest possible
-        // Decimal value to -0m.
-        private const decimal NearNegativeZero = -0.0000000000000000000000000001m;
-
-        // Constant representing the positive number that is the closest possible
-        // Decimal value to +0m.
-        private const decimal NearPositiveZero = +0.0000000000000000000000000001m;
-
         // The lo, mid, hi, and flags fields contain the representation of the
         // Decimal value. The lo, mid, and hi fields contain the 96-bit integer
         // part of the Decimal. Bits 0-15 (the lower word) of the flags field are
@@ -135,22 +103,10 @@ namespace System
         // NOTE: Do not change the order in which these fields are declared. The
         // native methods in this class rely on this particular order. 
         // Do not rename (binary serialization).
-        private int flags;
-        private int hi;
-        private int lo;
-        private int mid;
-
-        internal uint High => (uint)hi;
-        internal uint Low => (uint)lo;
-        internal uint Mid => (uint)mid;
-
-        // Constructs a zero Decimal.
-        //public Decimal() {
-        //    lo = 0;
-        //    mid = 0;
-        //    hi = 0;
-        //    flags = 0;
-        //}
+        private readonly int flags;
+        private readonly int hi;
+        private readonly int lo;
+        private readonly int mid;
 
         // Constructs a Decimal from an integer value.
         //
@@ -212,33 +168,60 @@ namespace System
 
         // Constructs a Decimal from a float value.
         //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern Decimal(float value);
+        public Decimal(float value)
+        {
+            DecCalc.VarDecFromR4(value, out AsMutable(ref this));
+        }
 
         // Constructs a Decimal from a double value.
         //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern Decimal(double value);
-
-        // Constructs a Decimal from a Currency value.
-        //
-        internal Decimal(Currency value)
+        public Decimal(double value)
         {
-            this = Currency.ToDecimal(value);
+            DecCalc.VarDecFromR8(value, out AsMutable(ref this));
         }
 
-        // Don't remove these 2 methods below. They are required by the fx when the are dealing with Currency in their
-        // databases
-        public static long ToOACurrency(decimal value)
+        //
+        // Decimal <==> Currency conversion.
+        //
+        // A Currency represents a positive or negative decimal value with 4 digits past the decimal point. The actual Int64 representation used by these methods
+        // is the currency value multiplied by 10,000. For example, a currency value of $12.99 would be represented by the Int64 value 129,900.
+        //
+        public static decimal FromOACurrency(long cy)
         {
-            return new Currency(value).ToOACurrency();
+            ulong absoluteCy; // has to be ulong to accommodate the case where cy == long.MinValue.
+            bool isNegative = false;
+            if (cy < 0)
+            {
+                isNegative = true;
+                absoluteCy = (ulong)(-cy);
+            }
+            else
+            {
+                absoluteCy = (ulong)cy;
+            }
+
+            // In most cases, FromOACurrency() produces a Decimal with Scale set to 4. Unless, that is, some of the trailing digits past the decimal point are zero,
+            // in which case, for compatibility with .Net, we reduce the Scale by the number of zeros. While the result is still numerically equivalent, the scale does
+            // affect the ToString() value. In particular, it prevents a converted currency value of $12.95 from printing uglily as "12.9500".
+            int scale = 4;
+            if (absoluteCy != 0)  // For compatibility, a currency of 0 emits the Decimal "0.0000" (scale set to 4).
+            {
+                while (scale != 0 && ((absoluteCy % 10) == 0))
+                {
+                    scale--;
+                    absoluteCy /= 10;
+                }
+            }
+
+            return new decimal((int)absoluteCy, (int)(absoluteCy >> 32), 0, isNegative, (byte)scale);
         }
 
-        public static decimal FromOACurrency(long cy)
+        public static long ToOACurrency(decimal value)
         {
-            return Currency.ToDecimal(Currency.FromOACurrency(cy));
+            return DecCalc.VarCyFromDec(ref AsMutable(ref value));
         }
 
+        private static bool IsValid(int flags) => (flags & ~(SignMask | ScaleMask)) == 0 && ((uint)(flags & ScaleMask) <= (28 << ScaleShift));
 
         // Constructs a Decimal from an integer array containing a binary
         // representation. The bits argument must be a non-null integer
@@ -266,7 +249,7 @@ namespace System
             if (bits.Length == 4)
             {
                 int f = bits[3];
-                if ((f & ~(SignMask | ScaleMask)) == 0 && (f & ScaleMask) <= (28 << 16))
+                if (IsValid(f))
                 {
                     lo = bits[0];
                     mid = bits[1];
@@ -292,40 +275,18 @@ namespace System
                 flags |= SignMask;
         }
 
-        [OnSerializing]
-        private void OnSerializing(StreamingContext ctx)
-        {
-            // OnSerializing is called before serialization of an object
-            try
-            {
-                // Run the constructor to validate the decimal
-                new decimal(lo, mid, hi, flags);
-            }
-            catch (ArgumentException e)
-            {
-                throw new SerializationException(SR.Overflow_Decimal, e);
-            }
-        }
-
         void IDeserializationCallback.OnDeserialization(object sender)
         {
             // OnDeserialization is called after each instance of this class is deserialized.
             // This callback method performs decimal validation after being deserialized.
-            try
-            {
-                // Run the constructor to validate the decimal
-                new decimal(lo, mid, hi, flags);
-            }
-            catch (ArgumentException e)
-            {
-                throw new SerializationException(SR.Overflow_Decimal, e);
-            }
+            if (!IsValid(flags))
+                throw new SerializationException(SR.Overflow_Decimal);
         }
 
         // Constructs a Decimal from its constituent parts.
         private Decimal(int lo, int mid, int hi, int flags)
         {
-            if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))
+            if (IsValid(flags))
             {
                 this.lo = lo;
                 this.mid = mid;
@@ -336,39 +297,38 @@ namespace System
             throw new ArgumentException(SR.Arg_DecBitCtor);
         }
 
+        private Decimal(in decimal d, int flags)
+        {
+            this = d;
+            this.flags = flags;
+        }
+
         // Returns the absolute value of the given Decimal. If d is
         // positive, the result is d. If d is negative, the result
         // is -d.
         //
         internal static decimal Abs(ref decimal d)
         {
-            return new decimal(d.lo, d.mid, d.hi, d.flags & ~SignMask);
+            return new decimal(in d, d.flags & ~SignMask);
         }
 
         // Adds two Decimal values.
         //
         public static decimal Add(decimal d1, decimal d2)
         {
-            FCallAddSub(ref d1, ref d2, DECIMAL_ADD);
+            DecCalc.DecAddSub(ref AsMutable(ref d1), ref AsMutable(ref d2), false);
             return d1;
         }
 
-        internal bool IsNegative => (flags & SignMask) != 0;
-
-        internal int Scale => (byte)((uint)flags >> ScaleShift);
-
-        // FCallAddSub adds or subtracts two decimal values.  On return, d1 contains the result
-        // of the operation.  Passing in DECIMAL_ADD or DECIMAL_NEG for bSign indicates
-        // addition or subtraction, respectively.
-        //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallAddSub(ref decimal d1, ref decimal d2, byte bSign);
 
         // Rounds a Decimal to an integer value. The Decimal argument is rounded
         // towards positive infinity.
         public static decimal Ceiling(decimal d)
         {
-            return (-(decimal.Floor(-d)));
+            int flags = d.flags;
+            if ((flags & ScaleMask) != 0)
+                DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Ceiling);
+            return d;
         }
 
         // Compares two Decimal values, returning an integer that indicates their
@@ -376,12 +336,9 @@ namespace System
         //
         public static int Compare(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2);
+            return DecCalc.VarDecCmp(in d1, in d2);
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern int FCallCompare(ref decimal d1, ref decimal d2);
-
         // Compares this object to another object, returning an integer that
         // indicates the relationship. 
         // Returns a value less than zero if this  object
@@ -396,29 +353,22 @@ namespace System
                 throw new ArgumentException(SR.Arg_MustBeDecimal);
 
             decimal other = (decimal)value;
-            return FCallCompare(ref this, ref other);
+            return DecCalc.VarDecCmp(in this, in other);
         }
 
         public int CompareTo(decimal value)
         {
-            return FCallCompare(ref this, ref value);
+            return DecCalc.VarDecCmp(in this, in value);
         }
 
         // Divides two Decimal values.
         //
         public static decimal Divide(decimal d1, decimal d2)
         {
-            FCallDivide(ref d1, ref d2);
+            DecCalc.VarDecDiv(ref AsMutable(ref d1), ref AsMutable(ref d2));
             return d1;
         }
 
-        // FCallDivide divides two decimal values.  On return, d1 contains the result
-        // of the operation.
-        //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallDivide(ref decimal d1, ref decimal d2);
-
-
         // Checks if this Decimal is equal to a given object. Returns true
         // if the given object is a boxed Decimal and its value is equal to the
         // value of this Decimal. Returns false otherwise.
@@ -428,26 +378,26 @@ namespace System
             if (value is decimal)
             {
                 decimal other = (decimal)value;
-                return FCallCompare(ref this, ref other) == 0;
+                return DecCalc.VarDecCmp(in this, in other) == 0;
             }
             return false;
         }
 
         public bool Equals(decimal value)
         {
-            return FCallCompare(ref this, ref value) == 0;
+            return DecCalc.VarDecCmp(in this, in value) == 0;
         }
 
         // Returns the hash code for this Decimal.
         //
-        public override int GetHashCode() => GetHashCode(ref this);
+        public override int GetHashCode() => DecCalc.GetHashCode(in this);
 
         // Compares two Decimal values for equality. Returns true if the two
         // Decimal values are equal, or false if they are not equal.
         //
         public static bool Equals(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) == 0;
+            return DecCalc.VarDecCmp(in d1, in d2) == 0;
         }
 
         // Rounds a Decimal to an integer value. The Decimal argument is rounded
@@ -455,13 +405,12 @@ namespace System
         //
         public static decimal Floor(decimal d)
         {
-            FCallFloor(ref d);
+            int flags = d.flags;
+            if ((flags & ScaleMask) != 0)
+                DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Floor);
             return d;
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallFloor(ref decimal d);
-
         // Converts this Decimal to a string. The resulting string consists of an
         // optional minus sign ("-") followed to a sequence of digits ("0" - "9"),
         // optionally followed by a decimal point (".") and another sequence of
@@ -615,171 +564,40 @@ namespace System
             return new decimal(lo, mid, hi, flags);
         }
 
-        // This method does a 'raw' and 'unchecked' addition of a UInt32 to a Decimal in place. 
-        // 'raw' means that it operates on the internal 96-bit unsigned integer value and 
-        // ingores the sign and scale. This means that it is not equivalent to just adding
-        // that number, as the sign and scale are effectively applied to the UInt32 value also.
-        // 'unchecked' means that it does not fail if you overflow the 96 bit value.
-        private static void InternalAddUInt32RawUnchecked(ref decimal value, uint i)
-        {
-            uint v;
-            uint sum;
-            v = (uint)value.lo;
-            sum = v + i;
-            value.lo = (int)sum;
-            if (sum < v || sum < i)
-            {
-                v = (uint)value.mid;
-                sum = v + 1;
-                value.mid = (int)sum;
-                if (sum < v || sum < 1)
-                {
-                    value.hi = (int)((uint)value.hi + 1);
-                }
-            }
-        }
-
-        // This method does an in-place division of a decimal by a UInt32, returning the remainder. 
-        // Although it does not operate on the sign or scale, this does not result in any 
-        // caveat for the result. It is equivalent to dividing by that number.
-        private static uint InternalDivRemUInt32(ref decimal value, uint divisor)
-        {
-            uint remainder = 0;
-            ulong n;
-            if (value.hi != 0)
-            {
-                n = ((uint)value.hi);
-                value.hi = (int)((uint)(n / divisor));
-                remainder = (uint)(n % divisor);
-            }
-            if (value.mid != 0 || remainder != 0)
-            {
-                n = ((ulong)remainder << 32) | (uint)value.mid;
-                value.mid = (int)((uint)(n / divisor));
-                remainder = (uint)(n % divisor);
-            }
-            if (value.lo != 0 || remainder != 0)
-            {
-                n = ((ulong)remainder << 32) | (uint)value.lo;
-                value.lo = (int)((uint)(n / divisor));
-                remainder = (uint)(n % divisor);
-            }
-            return remainder;
-        }
-
-        // Does an in-place round the specified number of digits, rounding mid-point values
-        // away from zero
-        private static void InternalRoundFromZero(ref decimal d, int decimalCount)
-        {
-            int scale = (d.flags & ScaleMask) >> ScaleShift;
-            int scaleDifference = scale - decimalCount;
-            if (scaleDifference <= 0)
-            {
-                return;
-            }
-            // Divide the value by 10^scaleDifference
-            uint lastRemainder;
-            uint lastDivisor;
-            do
-            {
-                int diffChunk = (scaleDifference > MaxInt32Scale) ? MaxInt32Scale : scaleDifference;
-                lastDivisor = Powers10[diffChunk];
-                lastRemainder = InternalDivRemUInt32(ref d, lastDivisor);
-                scaleDifference -= diffChunk;
-            } while (scaleDifference > 0);
-
-            // Round away from zero at the mid point
-            if (lastRemainder >= (lastDivisor >> 1))
-            {
-                InternalAddUInt32RawUnchecked(ref d, 1);
-            }
-
-            // the scale becomes the desired decimal count
-            d.flags = ((decimalCount << ScaleShift) & ScaleMask) | (d.flags & SignMask);
-        }
-
         // Returns the larger of two Decimal values.
         //
-        internal static decimal Max(ref decimal d1, ref decimal d2)
+        internal static ref decimal Max(ref decimal d1, ref decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) >= 0 ? d1 : d2;
+            return ref DecCalc.VarDecCmp(in d1, in d2) >= 0 ? ref d1 : ref d2;
         }
 
         // Returns the smaller of two Decimal values.
         //
-        internal static decimal Min(ref decimal d1, ref decimal d2)
+        internal static ref decimal Min(ref decimal d1, ref decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) < 0 ? d1 : d2;
+            return ref DecCalc.VarDecCmp(in d1, in d2) < 0 ? ref d1 : ref d2;
         }
 
         public static decimal Remainder(decimal d1, decimal d2)
         {
-            // OleAut doesn't provide a VarDecMod.            
-
-            // In the operation x % y the sign of y does not matter. Result will have the sign of x.
-            d2.flags = (d2.flags & ~SignMask) | (d1.flags & SignMask);
-
-
-            // This piece of code is to work around the fact that Dividing a decimal with 28 digits number by decimal which causes
-            // causes the result to be 28 digits, can cause to be incorrectly rounded up.
-            // eg. Decimal.MaxValue / 2 * Decimal.MaxValue will overflow since the division by 2 was rounded instead of being truncked.
-            if (Math.Abs(d1) < Math.Abs(d2))
-            {
-                return d1;
-            }
-            d1 -= d2;
-
-            if (d1 == 0)
-            {
-                // The sign of D1 will be wrong here. Fall through so that we still get a DivideByZeroException
-                d1.flags = (d1.flags & ~SignMask) | (d2.flags & SignMask);
-            }
-
-            // Formula:  d1 - (RoundTowardsZero(d1 / d2) * d2)            
-            decimal dividedResult = Truncate(d1 / d2);
-            decimal multipliedResult = dividedResult * d2;
-            decimal result = d1 - multipliedResult;
-            // See if the result has crossed 0
-            if ((d1.flags & SignMask) != (result.flags & SignMask))
-            {
-                if (NearNegativeZero <= result && result <= NearPositiveZero)
-                {
-                    // Certain Remainder operations on decimals with 28 significant digits round
-                    // to [+-]0.0000000000000000000000000001m instead of [+-]0m during the intermediate calculations. 
-                    // 'zero' results just need their sign corrected.
-                    result.flags = (result.flags & ~SignMask) | (d1.flags & SignMask);
-                }
-                else
-                {
-                    // If the division rounds up because it runs out of digits, the multiplied result can end up with a larger
-                    // absolute value and the result of the formula crosses 0. To correct it can add the divisor back.
-                    result += d2;
-                }
-            }
-
-            return result;
+            DecCalc.VarDecMod(ref AsMutable(ref d1), ref AsMutable(ref d2));
+            return d1;
         }
 
         // Multiplies two Decimal values.
         //
         public static decimal Multiply(decimal d1, decimal d2)
         {
-            FCallMultiply(ref d1, ref d2);
+            DecCalc.VarDecMul(ref AsMutable(ref d1), ref AsMutable(ref d2));
             return d1;
         }
 
-        // FCallMultiply multiples two decimal values.  On return, d1 contains the result
-        // of the operation.
-        //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallMultiply(ref decimal d1, ref decimal d2);
-
         // Returns the negated value of the given Decimal. If d is non-zero,
         // the result is -d. If d is zero, the result is zero.
         //
         public static decimal Negate(decimal d)
         {
-            return new decimal(d.lo, d.mid, d.hi, d.flags ^ SignMask);
+            return new decimal(in d, d.flags ^ SignMask);
         }
 
         // Rounds a Decimal value to a given number of decimal places. The value
@@ -790,52 +608,31 @@ namespace System
         // By default a mid-point value is rounded to the nearest even number. If the mode is
         // passed in, it can also round away from zero.
 
-        public static decimal Round(decimal d)
-        {
-            return Round(d, 0);
-        }
+        public static decimal Round(decimal d) => Round(ref d, 0, MidpointRounding.ToEven);
+        public static decimal Round(decimal d, int decimals) => Round(ref d, decimals, MidpointRounding.ToEven);
+        public static decimal Round(decimal d, MidpointRounding mode) => Round(ref d, 0, mode);
+        public static decimal Round(decimal d, int decimals, MidpointRounding mode) => Round(ref d, decimals, mode);
 
-        public static decimal Round(decimal d, int decimals)
+        private static decimal Round(ref decimal d, int decimals, MidpointRounding mode)
         {
-            FCallRound(ref d, decimals);
-            return d;
-        }
-
-        public static decimal Round(decimal d, MidpointRounding mode)
-        {
-            return Round(d, 0, mode);
-        }
-
-        public static decimal Round(decimal d, int decimals, MidpointRounding mode)
-        {
-            if ((decimals < 0) || (decimals > 28))
+            if ((uint)decimals > 28)
                 throw new ArgumentOutOfRangeException(nameof(decimals), SR.ArgumentOutOfRange_DecimalRound);
-            if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero)
-            {
+            if ((uint)mode > (uint)MidpointRounding.AwayFromZero)
                 throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
-            }
 
-            if (mode == MidpointRounding.ToEven)
-            {
-                FCallRound(ref d, decimals);
-            }
-            else
-            {
-                InternalRoundFromZero(ref d, decimals);
-            }
+            int scale = d.Scale - decimals;
+            if (scale > 0)
+                DecCalc.InternalRound(ref AsMutable(ref d), (uint)scale, (DecCalc.RoundingMode)mode);
             return d;
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallRound(ref decimal d, int decimals);
-
         internal static int Sign(ref decimal d) => (d.lo | d.mid | d.hi) == 0 ? 0 : (d.flags >> 31) | 1;
 
         // Subtracts two Decimal values.
         //
         public static decimal Subtract(decimal d1, decimal d2)
         {
-            FCallAddSub(ref d1, ref d2, DECIMAL_NEG);
+            DecCalc.DecAddSub(ref AsMutable(ref d1), ref AsMutable(ref d2), true);
             return d1;
         }
 
@@ -854,7 +651,7 @@ namespace System
             {
                 throw new OverflowException(SR.Overflow_Byte, e);
             }
-            if (temp < byte.MinValue || temp > byte.MaxValue) throw new OverflowException(SR.Overflow_Byte);
+            if (temp != (byte)temp) throw new OverflowException(SR.Overflow_Byte);
             return (byte)temp;
         }
 
@@ -874,7 +671,7 @@ namespace System
             {
                 throw new OverflowException(SR.Overflow_SByte, e);
             }
-            if (temp < sbyte.MinValue || temp > sbyte.MaxValue) throw new OverflowException(SR.Overflow_SByte);
+            if (temp != (sbyte)temp) throw new OverflowException(SR.Overflow_SByte);
             return (sbyte)temp;
         }
 
@@ -893,33 +690,17 @@ namespace System
             {
                 throw new OverflowException(SR.Overflow_Int16, e);
             }
-            if (temp < short.MinValue || temp > short.MaxValue) throw new OverflowException(SR.Overflow_Int16);
+            if (temp != (short)temp) throw new OverflowException(SR.Overflow_Int16);
             return (short)temp;
         }
 
-
-        // Converts a Decimal to a Currency. Since a Currency
-        // has fewer significant digits than a Decimal, this operation may
-        // produce round-off errors.
-        //
-        internal static Currency ToCurrency(decimal d)
-        {
-            Currency result = new Currency();
-            FCallToCurrency(ref result, d);
-            return result;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallToCurrency(ref Currency result, decimal d);
-
         // Converts a Decimal to a double. Since a double has fewer significant
         // digits than a Decimal, this operation may produce round-off errors.
         //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double ToDouble(decimal d);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern int FCallToInt32(decimal d);
+        public static double ToDouble(decimal d)
+        {
+            return DecCalc.VarR8FromDec(ref d);
+        }
 
         // Converts a Decimal to an integer. The Decimal value is rounded towards
         // zero to the nearest integer value, and the result of this operation is
@@ -927,11 +708,11 @@ namespace System
         //
         public static int ToInt32(decimal d)
         {
-            if ((d.flags & ScaleMask) != 0) FCallTruncate(ref d);
-            if (d.hi == 0 && d.mid == 0)
+            Truncate(ref d);
+            if ((d.hi | d.mid) == 0)
             {
                 int i = d.lo;
-                if (d.flags >= 0)
+                if (!d.IsNegative)
                 {
                     if (i >= 0) return i;
                 }
@@ -950,11 +731,11 @@ namespace System
         //
         public static long ToInt64(decimal d)
         {
-            if ((d.flags & ScaleMask) != 0) FCallTruncate(ref d);
+            Truncate(ref d);
             if (d.hi == 0)
             {
-                long l = d.lo & 0xFFFFFFFFL | (long)d.mid << 32;
-                if (d.flags >= 0)
+                long l = (long)d.Low64;
+                if (!d.IsNegative)
                 {
                     if (l >= 0) return l;
                 }
@@ -983,7 +764,7 @@ namespace System
             {
                 throw new OverflowException(SR.Overflow_UInt16, e);
             }
-            if (temp < ushort.MinValue || temp > ushort.MaxValue) throw new OverflowException(SR.Overflow_UInt16);
+            if (temp != (ushort)temp) throw new OverflowException(SR.Overflow_UInt16);
             return (ushort)temp;
         }
 
@@ -994,11 +775,11 @@ namespace System
         [CLSCompliant(false)]
         public static uint ToUInt32(decimal d)
         {
-            if ((d.flags & ScaleMask) != 0) FCallTruncate(ref d);
-            if (d.hi == 0 && d.mid == 0)
+            Truncate(ref d);
+            if ((d.hi | d.mid) == 0)
             {
-                uint i = (uint)d.lo;
-                if (d.flags >= 0 || i == 0)
+                uint i = d.Low;
+                if (!d.IsNegative || i == 0)
                     return i;
             }
             throw new OverflowException(SR.Overflow_UInt32);
@@ -1011,11 +792,11 @@ namespace System
         [CLSCompliant(false)]
         public static ulong ToUInt64(decimal d)
         {
-            if ((d.flags & ScaleMask) != 0) FCallTruncate(ref d);
+            Truncate(ref d);
             if (d.hi == 0)
             {
-                ulong l = ((ulong)(uint)d.lo) | ((ulong)(uint)d.mid << 32);
-                if (d.flags >= 0 || l == 0)
+                ulong l = d.Low64;
+                if (!d.IsNegative || l == 0)
                     return l;
             }
             throw new OverflowException(SR.Overflow_UInt64);
@@ -1024,8 +805,10 @@ namespace System
         // Converts a Decimal to a float. Since a float has fewer significant
         // digits than a Decimal, this operation may produce round-off errors.
         //
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float ToSingle(decimal d);
+        public static float ToSingle(decimal d)
+        {
+            return DecCalc.VarR4FromDec(ref d);
+        }
 
         // Truncates a Decimal to an integer value. The Decimal argument is rounded
         // towards zero to the nearest integer value, corresponding to removing all
@@ -1033,14 +816,17 @@ namespace System
         //
         public static decimal Truncate(decimal d)
         {
-            FCallTruncate(ref d);
+            Truncate(ref d);
             return d;
         }
 
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern void FCallTruncate(ref decimal d);
-
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static void Truncate(ref decimal d)
+        {
+            int flags = d.flags;
+            if ((flags & ScaleMask) != 0)
+                DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Truncate);
+        }
 
         public static implicit operator decimal(byte value)
         {
@@ -1192,26 +978,22 @@ namespace System
 
         public static decimal operator +(decimal d1, decimal d2)
         {
-            FCallAddSub(ref d1, ref d2, DECIMAL_ADD);
-            return d1;
+            return Add(d1, d2);
         }
 
         public static decimal operator -(decimal d1, decimal d2)
         {
-            FCallAddSub(ref d1, ref d2, DECIMAL_NEG);
-            return d1;
+            return Subtract(d1, d2);
         }
 
         public static decimal operator *(decimal d1, decimal d2)
         {
-            FCallMultiply(ref d1, ref d2);
-            return d1;
+            return Multiply(d1, d2);
         }
 
         public static decimal operator /(decimal d1, decimal d2)
         {
-            FCallDivide(ref d1, ref d2);
-            return d1;
+            return Divide(d1, d2);
         }
 
         public static decimal operator %(decimal d1, decimal d2)
@@ -1221,32 +1003,32 @@ namespace System
 
         public static bool operator ==(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) == 0;
+            return DecCalc.VarDecCmp(in d1, in d2) == 0;
         }
 
         public static bool operator !=(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) != 0;
+            return DecCalc.VarDecCmp(in d1, in d2) != 0;
         }
 
         public static bool operator <(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) < 0;
+            return DecCalc.VarDecCmp(in d1, in d2) < 0;
         }
 
         public static bool operator <=(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) <= 0;
+            return DecCalc.VarDecCmp(in d1, in d2) <= 0;
         }
 
         public static bool operator >(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) > 0;
+            return DecCalc.VarDecCmp(in d1, in d2) > 0;
         }
 
         public static bool operator >=(decimal d1, decimal d2)
         {
-            return FCallCompare(ref d1, ref d2) >= 0;
+            return DecCalc.VarDecCmp(in d1, in d2) >= 0;
         }
 
         //
index c764f08..9b9bf66 100644 (file)
@@ -1466,6 +1466,83 @@ namespace System
             return result;
         }
 
+        private static unsafe bool NumberBufferToDecimal(ref NumberBuffer number, ref decimal value)
+        {
+            decimal d = new decimal();
+
+            char* p = number.digits;
+            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 > DecimalPrecision)
+                    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'))))))))
+                {
+                    decimal.DecMul10(ref d);
+                    if (*p != 0)
+                        decimal.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 roundinp 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)
+                    {
+                        decimal.DecAddInt32(ref d, 1);
+                        if ((d.High | d.Mid | d.Low) == 0)
+                        {
+                            d = new decimal(unchecked((int)0x9999999A), unchecked((int)0x99999999), 0x19999999, false, 0);
+                            e++;
+                        }
+                    }
+                }
+            }
+
+            if (e > 0)
+                return false;
+
+            if (e <= -DecimalPrecision)
+            {
+                // 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.
+                value = new decimal(0, 0, 0, number.sign, DecimalPrecision - 1);
+            }
+            else
+            {
+                value = new decimal((int)d.Low, (int)d.Mid, (int)d.High, number.sign, (byte)-e);
+            }
+            return true;
+        }
+
         internal static double ParseDouble(ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info)
         {
             NumberBuffer number = default;