System.Data.SqlTypes.SqlDecimal.MpDiv C# (CSharp) Method

MpDiv() private static method

private static MpDiv ( uint rgulU, int ciulU, uint rgulD, int ciulD, uint rgulQ, int &ciulQ, uint rgulR, int &ciulR ) : void
rgulU uint
ciulU int
rgulD uint
ciulD int
rgulQ uint
ciulQ int
rgulR uint
ciulR int
return void
        private static void MpDiv
        (
        uint[] rgulU,      // In    | U
        int ciulU,      // In    | # of digits in U
        uint[] rgulD,      // In    | D
        int ciulD,      // In    | # of digits in D
        uint[] rgulQ,      // Out    | Q
        out int ciulQ,      // Out    | # of digits in Q
        uint[] rgulR,      // Out    | R
        out int ciulR       // Out    | # of digits in R
        )
        {
            Debug.Assert(ciulU > 0, "ciulU > 0", "In method MpDiv");
            Debug.Assert(ciulD > 0, "ciulD > 0", "In method MpDiv");
            Debug.Assert(rgulU.Length == s_cNumeMax);
            Debug.Assert(rgulD.Length == s_cNumeMax);

            // Division by zero?
            if (ciulD == 1 && rgulD[0] == 0)
            {
                ciulQ = ciulR = 0;
            }

            // Check for simplest case, so it'll be fast
            else if (ciulU == 1 && ciulD == 1)
            {
                MpSet(rgulQ, out ciulQ, rgulU[0] / rgulD[0]);
                MpSet(rgulR, out ciulR, rgulU[0] % rgulD[0]);
            }

            // If D > U then do not divide at all
            else if (ciulD > ciulU)
            {
                MpMove(rgulU, ciulU, rgulR, out ciulR);        // R = U
                MpSet(rgulQ, out ciulQ, 0);                    // Q = 0
            }

            // Try to divide faster - check for remaining good sizes (8 / 4, 8 / 8)
            else if (ciulU <= 2)
            {
                ulong dwlU, dwlD, dwlT;

                dwlU = DWL(rgulU[0], rgulU[1]);
                dwlD = rgulD[0];
                if (ciulD > 1)
                    dwlD += (((ulong)rgulD[1]) << 32);
                dwlT = dwlU / dwlD;
                rgulQ[0] = LO(dwlT);
                rgulQ[1] = HI(dwlT);
                ciulQ = (HI(dwlT) != 0) ? 2 : 1;
                dwlT = dwlU % dwlD;
                rgulR[0] = LO(dwlT);
                rgulR[1] = HI(dwlT);
                ciulR = (HI(dwlT) != 0) ? 2 : 1;
            }

            // If we are dividing by one digit - use simpler routine
            else if (ciulD == 1)
            {
                MpMove(rgulU, ciulU, rgulQ, out ciulQ);        // Q = U
                uint remainder;
                MpDiv1(rgulQ, ref ciulQ, rgulD[0], out remainder);     // Q = Q / D, R = Q % D
                rgulR[0] = remainder;
                ciulR = 1;
            }

            // Worst case. Knuth, "The Art of Computer Programming", 3rd edition, vol.II, Alg.D, pg 272
            else
            {
                ciulQ = ciulR = 0;

                uint D1, ulDHigh, ulDSecond;
                int iulRindex;

                if (rgulU != rgulR)
                    MpMove(rgulU, ciulU, rgulR, out ciulR);        // R = U

                ciulQ = ciulU - ciulD + 1;
                ulDHigh = rgulD[ciulD - 1];

                // D1.    Normalize so high digit of D >= BASE/2 - that guarantee
                //        that QH will not be too far from the correct digit later in D3
                rgulR[ciulU] = 0;
                iulRindex = ciulU;
                D1 = (uint)(s_ulInt32Base / ((ulong)ulDHigh + 1));
                if (D1 > 1)
                {
                    MpMul1(rgulD, ref ciulD, D1);
                    ulDHigh = rgulD[ciulD - 1];
                    MpMul1(rgulR, ref ciulR, D1);
                }
                ulDSecond = rgulD[ciulD - 2];
                // D2 already done - iulRindex initialized before normalization of R.
                // D3-D7. Loop on iulRindex - obtaining digits one-by-one, as "in paper"
                do
                {
                    uint QH, RH;
                    int iulDindex, iulRwork;
                    ulong dwlAccum, dwlMulAccum;

                    // D3. Calculate Q hat - estimation of the next digit
                    dwlAccum = DWL(rgulR[iulRindex - 1], rgulR[iulRindex]);
                    if (ulDHigh == rgulR[iulRindex])
                        QH = (uint)(s_ulInt32Base - 1);
                    else
                        QH = (uint)(dwlAccum / ulDHigh);
                    ulong ulTemp = QH;
                    RH = (uint)(dwlAccum - ulTemp * ulDHigh);

                    while (ulDSecond * ulTemp > DWL(rgulR[iulRindex - 2], RH))
                    {
                        QH--;
                        if (RH >= (uint)-((int)ulDHigh))
                            break;
                        RH += ulDHigh;
                        ulTemp = QH;
                    }

                    // D4. Multiply and subtract: (some digits of) R -= D * QH
                    for (dwlAccum = s_ulInt32Base, dwlMulAccum = 0, iulDindex = 0, iulRwork = iulRindex - ciulD;
                        iulDindex < ciulD; iulDindex++, iulRwork++)
                    {
                        ulong ulTemp2 = rgulD[iulDindex];
                        dwlMulAccum += QH * ulTemp2;
                        dwlAccum += (ulong)rgulR[iulRwork] - LO(dwlMulAccum);
                        dwlMulAccum = HI(dwlMulAccum);
                        rgulR[iulRwork] = LO(dwlAccum);
                        dwlAccum = HI(dwlAccum) + s_ulInt32Base - 1;
                    }
                    dwlAccum += rgulR[iulRwork] - dwlMulAccum;
                    rgulR[iulRwork] = LO(dwlAccum);
                    rgulQ[iulRindex - ciulD] = QH;

                    // D5. Test remainder. Carry indicates result<0, therefore QH 1 too large
                    if (HI(dwlAccum) == 0)
                    {
                        // D6. Add back - probabilty is 2**(-31). R += D. Q[digit] -= 1
                        uint ulCarry;

                        rgulQ[iulRindex - ciulD] = QH - 1;
                        for (ulCarry = 0, iulDindex = 0, iulRwork = iulRindex - ciulD;
                            iulDindex < ciulD; iulDindex++, iulRwork++)
                        {
                            dwlAccum = rgulD[iulDindex] + (ulong)rgulR[iulRwork] + ulCarry;
                            ulCarry = HI(dwlAccum);
                            rgulR[iulRwork] = LO(dwlAccum);
                        }
                        rgulR[iulRwork] += ulCarry;
                    }
                    // D7. Loop on iulRindex
                    iulRindex--;
                }
                while (iulRindex >= ciulD);
                // Normalize results
                MpNormalize(rgulQ, ref ciulQ);
                ciulR = ciulD;
                MpNormalize(rgulR, ref ciulR);
                // D8. Unnormalize: Divide D and R to get result
                if (D1 > 1)
                {
                    uint ret;
                    MpDiv1(rgulD, ref ciulD, D1, out ret);
                    MpDiv1(rgulR, ref ciulR, D1, out ret);
                }
            }
        }