SetPositive() private method

private SetPositive ( ) : void
return void
Example #1
0
        private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate)
        {
            if (n.IsNull)
                return SqlDecimal.Null;

            if (lPosition >= 0)
            {
                //If round to the right of decimal number
                lPosition = Math.Min(s_NUMERIC_MAX_PRECISION, lPosition);
                if (lPosition >= n.m_bScale)
                    return n;   //No need to round
            }
            else
            {
                //If round to the left of the decimal point
                lPosition = Math.Max(-s_NUMERIC_MAX_PRECISION, lPosition);

                //Return +0.00 if truncation of integer part
                if (lPosition < n.m_bScale - n.m_bPrec)
                {
                    n.SetToZero();
                    return n;
                }
            }

            uint ulRem = 0;                                         // Remainder: the highest significant digit to be truncated
            int lAdjust = Math.Abs(lPosition - (int)n.m_bScale);    // Precision adjustment
            uint ulLastDivBase = 1;                                 //

            //Compute the integral part of the numeric
            while (lAdjust > 0)
            {
                if (lAdjust >= 9)
                {
                    ulRem = n.DivByULong(s_rgulShiftBase[8]);
                    ulLastDivBase = s_rgulShiftBase[8];
                    lAdjust -= 9;
                }
                else
                {
                    ulRem = n.DivByULong(s_rgulShiftBase[lAdjust - 1]);
                    ulLastDivBase = s_rgulShiftBase[lAdjust - 1];
                    lAdjust = 0;
                }
            }

            // The rounding only depends on the first digit after the rounding position
            if (ulLastDivBase > 1)
            {
                ulRem /= (ulLastDivBase / 10);
            }

            //If result is zero, return
            if (n.FZero() && (fTruncate || ulRem < 5))
            {
                n.SetPositive();
                n.AssertValid();
                return n;
            }

            // Adjust by adding 1 if remainder is larger than 5
            if (ulRem >= 5 && !fTruncate)
                n.AddULong(1);

            // Convert back to original scale
            lAdjust = Math.Abs(lPosition - n.m_bScale);

            while (lAdjust-- > 0)
            {
                n.MultByULong(s_ulBase10);
            }

            n.AssertValid();
            return n;
        }
Example #2
0
        // Builtin functions

        // Abs - absolute value
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static SqlDecimal Abs(SqlDecimal n)
        {
            n.AssertValid();

            if (n.IsNull)
                return SqlDecimal.Null;

            n.SetPositive();
            n.AssertValid();
            return n;
        }
Example #3
0
        // Floor - next largest integer smaller or equal to the numeric
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static SqlDecimal Floor(SqlDecimal n)
        {
            n.AssertValid();

            if (n.IsNull)
                return SqlDecimal.Null;

            if (n.m_bScale == 0)
                return n;

            bool fFraction;    //Fractional flag

            n.MakeInteger(out fFraction);

            //When the numeric has fraction and is negative, subtract 1 by calling AddULong(1)
            //Otherwise return the integral part.
            if (fFraction && !n.IsPositive)
            {
                n.AddULong(1);
            }

            if (n.FZero())//if result is zero, sign should be positive
                n.SetPositive();
            n.AssertValid();
            return n;
        }
Example #4
0
        //    MultNm()
        //
        //    Multiply two numerics.
        //
        //  Parameters:
        //        x    - IN Multiplier
        //        y    - IN Multiplicand
        //
        //    Result scale and precision(same as in SQL Server Manual and Hydra):
        //        scale = s1 + s2
        //        precision = s1 + s2 + (p1 - s1) + (p2 - s2) + 1
        //
        //    Overflow Rules:
        //        If scale is greater than NUMERIC_MAX_PRECISION it is set to
        //    NUMERIC_MAX_PRECISION.  If precision is greater than NUMERIC_MAX_PRECISION
        //    it is set to NUMERIC_MAX_PRECISION, then scale is reduced to keep the
        //    integer part untruncated but keeping a minimum value of x_cNumeDivScaleMin.
        //    For example, if using the above formula, the resulting precision is 46 and
        //    scale is 10, the precision will be reduced to 38. To keep the integral part
        //    untruncated the scale needs be reduced to 2, but since x_cNumeDivScaleMin
        //    is set to 6 currently, resulting scale will be 6.
        //        O_OVERFLOW is returned only if the actual precision is greater than
        //     NUMERIC_MAX_PRECISION or the actual length is greater than x_cbNumeBuf.
        //
        //    Algorithm:
        //        Starting from the lowest significant UI4, for each UI4 of the multiplier
        //    iterate through the UI4s of the multiplicand starting from
        //    the least significant UI4s, multiply the multiplier UI4 with
        //    multiplicand UI4, update the result buffer with the product modulo
        //    x_dwlBaseUI4 at the same index as the multiplicand, and carry the quotient to
        //    add to the next multiplicand UI4.  Until the end of the multiplier data
        //    array is reached.
        //
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y)
        {
            x.AssertValid();
            y.AssertValid();

            if (x.IsNull || y.IsNull)
                return Null;

            //Implementation:
            //        I) Figure result scale,prec
            //        II) Perform mult.
            //        III) Adjust product to result scale,prec

            // Local variables for actual multiplication
            int iulPlier;           //index of UI4 in the Multiplier
            uint ulPlier;            //current multiplier UI4
            ulong dwlAccum;           //accumulated sum
            ulong dwlNextAccum;       //overflow of accumulated sum
            int culCand = y.m_bLen; //length of multiplicand in UI4s

            //Local variables to track scale,precision
            int ActualScale;                    // Scale after mult done
            int ResScale;                       // Final scale we will force result to
            int ResPrec;                        // Final precision we will force result to
            int ResInteger;                     // # of digits in integer part of result (prec-scale)
            int lScaleAdjust;   //How much result scale will be adjusted
            bool fResPositive;  // Result sign

            SqlDecimal ret;


            //I) Figure result prec,scale
            ActualScale = x.m_bScale + y.m_bScale;
            ResScale = ActualScale;
            ResInteger = (x.m_bPrec - x.m_bScale) + (y.m_bPrec - y.m_bScale) + 1;

            //result precision = s1 + s2 + (p1 - s1) + (p2 - s2) + 1
            ResPrec = ResScale + ResInteger;

            // Downward adjust res prec,scale if either larger than NUMERIC_MAX_PRECISION
            if (ResPrec > s_NUMERIC_MAX_PRECISION)
                ResPrec = s_NUMERIC_MAX_PRECISION;
            if (ResScale > s_NUMERIC_MAX_PRECISION)
                ResScale = s_NUMERIC_MAX_PRECISION;

            //
            // It is possible when two large numbers are being multiplied the scale
            // can be reduced to 0 to keep data untruncated; the fix here is to
            // preserve a minimum scale of 6.
            //
            // If overflow, reduce the scale to avoid truncation of data
            ResScale = Math.Min((ResPrec - ResInteger), ResScale);
            // But keep a minimum scale of NUMERIC_MIN_DVSCALE
            ResScale = Math.Max(ResScale, Math.Min(ActualScale, s_cNumeDivScaleMin));

            lScaleAdjust = ResScale - ActualScale;

            fResPositive = (x.IsPositive == y.IsPositive);//positive if both signs same.

            // II) Perform multiplication

            uint[] rglData1 = new uint[4] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 };
            uint[] rglData2 = new uint[4] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 };

            //Local buffer to hold the result of multiplication.
            //Longer than CReNumeBuf because full precision of multiplication is carried out
            const int x_culNumeMultRes = 9;       // Maximum # UI4s in result buffer in multiplication
            uint[] rgulRes = new uint[x_culNumeMultRes]; //new [] are already initialized to zero
            int culRes;             // # of UI4s in result
            int idRes = 0;

            //Iterate over the bytes of multiplier
            for (iulPlier = 0; iulPlier < x.m_bLen; iulPlier++)
            {
                ulPlier = rglData1[iulPlier];
                dwlAccum = 0;

                //Multiply each UI4 of multiCand by ulPliear and accumulate into result buffer

                // Start on correct place in result
                idRes = iulPlier;

                for (int iulCand = 0; iulCand < culCand; iulCand++)
                {
                    // dwlAccum = dwlAccum + rgulRes[idRes] + ulPlier*rglData2[iulCand]
                    //        use dwlNextAccum to detect overflow of DWORDLONG
                    dwlNextAccum = dwlAccum + rgulRes[idRes];
                    ulong ulTemp = (ulong)rglData2[iulCand];
                    dwlAccum = (ulong)ulPlier * ulTemp;
                    dwlAccum += dwlNextAccum;
                    if (dwlAccum < dwlNextAccum) // indicates dwl addition overflowed
                        dwlNextAccum = s_ulInt32Base; // = maxUI64/x_dwlBaseUI4
                    else
                        dwlNextAccum = 0;

                    // Update result and accum
                    rgulRes[idRes++] = (uint)(dwlAccum);// & x_ulInt32BaseForMod); // equiv to mod x_lInt32Base
                    dwlAccum = (dwlAccum >> 32) + dwlNextAccum; // equiv to div BaseUI4 + dwlNAccum

                    // dwlNextAccum can't overflow next iteration
                    Debug.Assert(dwlAccum < s_ulInt32Base * 2);
                }

                Debug.Assert(dwlAccum < s_ulInt32Base); // can never final accum > 1 more UI4
                if (dwlAccum != 0)
                    rgulRes[idRes++] = (uint)dwlAccum;
            }
            // Skip leading 0s (may exist if we are multiplying by 0)
            for (; (rgulRes[idRes] == 0) && (idRes > 0); idRes--)
                ;
            // Calculate actual result length
            culRes = idRes + 1;

            // III) Adjust precision,scale to result prec,scale
            if (lScaleAdjust != 0)
            {
                // If need to decrease scale
                if (lScaleAdjust < 0)
                {
                    Debug.Assert(s_NUMERIC_MAX_PRECISION == ResPrec);

                    // have to adjust - might yet end up fitting.
                    // Cannot call AdjustScale - number cannot fit in a numeric, so
                    // have to duplicate code here

                    uint ulRem;          //Remainder when downshifting
                    uint ulShiftBase;    //What to multiply by to effect scale adjust

                    do
                    {
                        if (lScaleAdjust <= -9)
                        {
                            ulShiftBase = s_rgulShiftBase[8];
                            lScaleAdjust += 9;
                        }
                        else
                        {
                            ulShiftBase = s_rgulShiftBase[-lScaleAdjust - 1];
                            lScaleAdjust = 0;
                        }
                        MpDiv1(rgulRes, ref culRes, ulShiftBase, out ulRem);
                    }
                    while (lScaleAdjust != 0);

                    // Still do not fit?
                    if (culRes > s_cNumeMax)
                        throw new OverflowException(SQLResource.ArithOverflowMessage);

                    for (idRes = culRes; idRes < s_cNumeMax; idRes++)
                        rgulRes[idRes] = 0;
                    ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive);

                    // Is it greater than 10**38?
                    if (ret.FGt10_38())
                        throw new OverflowException(SQLResource.ArithOverflowMessage);

                    ret.AssertValid();

                    // If remainder is 5 or above, increment/decrement by 1.
                    if (ulRem >= ulShiftBase / 2)
                        ret.AddULong(1);
                    // After adjusting, if the result is 0 and remainder is less than 5,
                    // set the sign to be positive
                    if (ret.FZero())
                        ret.SetPositive();

                    return ret;
                }

                // Otherwise call AdjustScale
                if (culRes > s_cNumeMax)    // Do not fit now, so will not fit after adjustment
                    throw new OverflowException(SQLResource.ArithOverflowMessage);
                // NOTE: Have not check for value in the range (10**38..2**128),
                // as we'll call AdjustScale with positive argument, and it'll
                // return "normal" overflow

                for (idRes = culRes; idRes < s_cNumeMax; idRes++)
                    rgulRes[idRes] = 0;
                ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ActualScale, fResPositive);

                if (ret.FZero())
                    ret.SetPositive();

                ret.AssertValid();

                ret.AdjustScale(lScaleAdjust, true);

                return ret;
            }
            else
            {
                if (culRes > s_cNumeMax)
                    throw new OverflowException(SQLResource.ArithOverflowMessage);

                for (idRes = culRes; idRes < s_cNumeMax; idRes++)
                    rgulRes[idRes] = 0;
                ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive);

                // Is it greater than 10**38?
                if (ret.FGt10_38())
                    throw new OverflowException(SQLResource.ArithOverflowMessage);

                if (ret.FZero())
                    ret.SetPositive();

                ret.AssertValid();

                return ret;
            }
        }
Example #5
0
        //-----------------------------------------------------------
        //DivNm():
        //  Divide numeric by numeric.
        //    The Quotient will be returned in *this
        //
        //Result scale & precision:
        //    NOTE: same as in Hydra but different from SQL Server Manual,
        //            where scale = max(s1+p2-s2+1,x_cNumeDivScaleMin)):
        //        scale = max(s1 + p2 + 1, x_cNumeDivScaleMin);
        //        precision = max(s1 + p2 + 1, x_cNumeDivScaleMin) + p1 + p2 + 1;
        //
        //Overflow Rules:
        //        If scale is greater than NUMERIC_MAX_PRECISION it is set to
        //    NUMERIC_MAX_PRECISION.  If precision is greater than NUMERIC_MAX_PRECISION
        //    it's set to NUMERIC_MAX_PRECISION, then scale is reduced to keep the
        //    integer part untruncated but keeping a minimum value of x_cNumeDivScaleMin.
        //    For example, if using the above formula, the resulting precision is 46 and
        //    scale is 10, the precision will be reduced to 38, to keep the integral part
        //    untruncated the scale needs be reduced to 2, but since x_cNumeDivScaleMin
        //    is set to 6 currently, resulting scale will be 6.
        //        OverflowException is thrown only if the actual precision is greater than
        //    NUMERIC_MAX_PRECISION or actual length is greater than x_cbNumeBuf
        //
        //Algorithm
        //  Call general purpose arbitrary precision division routine with scale = 0.
        //    Scale,prec adjusted later.
        //
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static SqlDecimal operator /(SqlDecimal x, SqlDecimal y)
        {
            if (x.IsNull || y.IsNull)
                return Null;

            x.AssertValid();
            y.AssertValid();

            // Variables for figuring prec,scale
            int bScaleD;            // Input Scale of dividend (output scale of remainder)
            int bPrecD;             // Input Prec of dividend (output prec of remainder)
            int ResScale;           // Final scale we will force quotient to
            int ResPrec;            // Final precision we will force quotient to
            int ResInteger;         // # of digits in integer part of result (prec-scale)
            int MinScale;           // Temp to help compute ResScale
            int lScaleAdjust;       // How much result scale will be adjusted
            bool fResSignPos;       // sign of result

            // Steps:
            //    1) Figure result prec,scale; adjust scale of dividend
            //    2) Compute result remainder/quotient in 0 scale numbers
            //    3) Set result prec,scale and adjust as necessary

            // 0) Check for Div by 0
            if (y.FZero())
                throw new DivideByZeroException(SQLResource.DivideByZeroMessage);

            // 1) Figure out result prec,scale,sign..
            fResSignPos = (x.IsPositive == y.IsPositive);//sign of result

            //scale = max(s1 + p2 + 1, x_cNumeDivScaleMin);
            //precision = max(s1 + p2 + 1, x_cNumeDivScaleMin) + p1 + p2 + 1;
            //For backward compatibility, use exactly the same scheme as in Hydra
            bScaleD = x.m_bScale;
            bPrecD = x.m_bPrec;
            ResScale = Math.Max(x.m_bScale + y.m_bPrec + 1, s_cNumeDivScaleMin);
            ResInteger = x.m_bPrec - x.m_bScale + y.m_bScale;
            MinScale = Math.Min(ResScale, s_cNumeDivScaleMin);

            ResInteger = Math.Min(ResInteger, s_NUMERIC_MAX_PRECISION);
            ResPrec = ResInteger + ResScale;

            if (ResPrec > s_NUMERIC_MAX_PRECISION)
                ResPrec = s_NUMERIC_MAX_PRECISION;

            // If overflow, reduce the scale to avoid truncation of data
            ResScale = Math.Min((ResPrec - ResInteger), ResScale);
            ResScale = Math.Max(ResScale, MinScale);

            //Adjust the scale of the dividend
            lScaleAdjust = ResScale - (int)x.m_bScale + (int)y.m_bScale;
            x.AdjustScale(lScaleAdjust, true);

            // Step2: Actual Computation

            uint[] rgulData1 = new uint[4] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 };
            uint[] rgulData2 = new uint[4] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 };

            // Buffers for arbitrary precision divide
            uint[] rgulR = new uint[s_cNumeMax + 1];
            uint[] rgulQ = new uint[s_cNumeMax];
            // # of ULONGs in result
            int culQ, culR;

            // Divide mantissas. V is not zero - already checked.
            // Cannot overflow, as Q <= U, R <= V. (and both are positive)
            MpDiv(rgulData1, x.m_bLen, rgulData2, y.m_bLen, rgulQ, out culQ, rgulR, out culR);

            // Construct the result from Q
            ZeroToMaxLen(rgulQ, culQ);
            SqlDecimal ret = new SqlDecimal(rgulQ, (byte)culQ, (byte)ResPrec, (byte)ResScale, fResSignPos);

            if (ret.FZero())
                ret.SetPositive();

            ret.AssertValid();

            return ret;
        }
 public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y)
 {
     SqlDecimal num11;
     if (x.IsNull || y.IsNull)
     {
         return Null;
     }
     int bLen = y.m_bLen;
     int num10 = x.m_bScale + y.m_bScale;
     int num3 = num10;
     int num13 = ((x.m_bPrec - x.m_bScale) + (y.m_bPrec - y.m_bScale)) + 1;
     int num6 = num3 + num13;
     if (num6 > NUMERIC_MAX_PRECISION)
     {
         num6 = NUMERIC_MAX_PRECISION;
     }
     if (num3 > NUMERIC_MAX_PRECISION)
     {
         num3 = NUMERIC_MAX_PRECISION;
     }
     num3 = Math.Max(Math.Min(num6 - num13, num3), Math.Min(num10, x_cNumeDivScaleMin));
     int digits = num3 - num10;
     bool fPositive = x.IsPositive == y.IsPositive;
     uint[] numArray5 = new uint[] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 };
     uint[] numArray4 = new uint[] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 };
     uint[] rgulU = new uint[9];
     int index = 0;
     for (int i = 0; i < x.m_bLen; i++)
     {
         uint num16 = numArray5[i];
         ulong num2 = 0L;
         index = i;
         for (int j = 0; j < bLen; j++)
         {
             ulong num7 = num2 + rgulU[index];
             ulong num15 = numArray4[j];
             num2 = num16 * num15;
             num2 += num7;
             if (num2 < num7)
             {
                 num7 = x_ulInt32Base;
             }
             else
             {
                 num7 = 0L;
             }
             rgulU[index++] = (uint) num2;
             num2 = (num2 >> 0x20) + num7;
         }
         if (num2 != 0L)
         {
             rgulU[index++] = (uint) num2;
         }
     }
     while ((rgulU[index] == 0) && (index > 0))
     {
         index--;
     }
     int ciulU = index + 1;
     if (digits != 0)
     {
         if (digits < 0)
         {
             uint num12;
             uint num14;
             do
             {
                 if (digits <= -9)
                 {
                     num12 = x_rgulShiftBase[8];
                     digits += 9;
                 }
                 else
                 {
                     num12 = x_rgulShiftBase[-digits - 1];
                     digits = 0;
                 }
                 MpDiv1(rgulU, ref ciulU, num12, out num14);
             }
             while (digits != 0);
             if (ciulU > x_cNumeMax)
             {
                 throw new OverflowException(SQLResource.ArithOverflowMessage);
             }
             for (index = ciulU; index < x_cNumeMax; index++)
             {
                 rgulU[index] = 0;
             }
             num11 = new SqlDecimal(rgulU, (byte) ciulU, (byte) num6, (byte) num3, fPositive);
             if (num11.FGt10_38())
             {
                 throw new OverflowException(SQLResource.ArithOverflowMessage);
             }
             if (num14 >= (num12 / 2))
             {
                 num11.AddULong(1);
             }
             if (num11.FZero())
             {
                 num11.SetPositive();
             }
             return num11;
         }
         if (ciulU > x_cNumeMax)
         {
             throw new OverflowException(SQLResource.ArithOverflowMessage);
         }
         for (index = ciulU; index < x_cNumeMax; index++)
         {
             rgulU[index] = 0;
         }
         num11 = new SqlDecimal(rgulU, (byte) ciulU, (byte) num6, (byte) num10, fPositive);
         if (num11.FZero())
         {
             num11.SetPositive();
         }
         num11.AdjustScale(digits, true);
         return num11;
     }
     if (ciulU > x_cNumeMax)
     {
         throw new OverflowException(SQLResource.ArithOverflowMessage);
     }
     for (index = ciulU; index < x_cNumeMax; index++)
     {
         rgulU[index] = 0;
     }
     num11 = new SqlDecimal(rgulU, (byte) ciulU, (byte) num6, (byte) num3, fPositive);
     if (num11.FGt10_38())
     {
         throw new OverflowException(SQLResource.ArithOverflowMessage);
     }
     if (num11.FZero())
     {
         num11.SetPositive();
     }
     return num11;
 }
Example #7
0
        // Binary operators

        // Arithmetic operators
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y)
        {
            if (x.IsNull || y.IsNull)
                return Null;

            ulong dwlAccum;           //accumulated sum
            bool fMySignPos;         //sign of x was positive at start
            bool fOpSignPos;         // sign of y positive at start
            bool fResSignPos = true; //sign of result should be positive
            int MyScale;    //scale of x
            int OpScale;    //scale of y
            int ResScale;   //scale of result
            int ResPrec;    //precision of result
            int ResInteger; //number of digits for the integer part of result
            int culOp1;     //# of UI4s in x
            int culOp2;     //# of UI4s in y
            int iulData;    //which UI4 we are operating on in x, y
            byte bLen;       // length for the result


            x.AssertValid();
            y.AssertValid();

            fMySignPos = x.IsPositive;
            fOpSignPos = y.IsPositive;

            //result scale = max(s1,s2)
            //result precision = max(s1,s2) + max(p1-s1,p2-s2)
            MyScale = x.m_bScale;
            OpScale = y.m_bScale;

            // Calculate the integer part of the result.
            ResInteger = Math.Max((int)x.m_bPrec - MyScale, (int)y.m_bPrec - OpScale);
            Debug.Assert(ResInteger <= MaxPrecision);

            // Calculate the scale of the result.
            ResScale = Math.Max(MyScale, OpScale);
            Debug.Assert(ResScale <= MaxScale);

            // Calculate the precision of the result.
            // Add 1 for final carry.
            ResPrec = ResInteger + ResScale + 1;
            ResPrec = Math.Min(MaxPrecision, ResPrec);

            // If precision adjusted, scale is reduced to keep the integer part untruncated.
            // But discard the extra carry, only keep the integer part as ResInteger, not ResInteger + 1.
            Debug.Assert(ResPrec - ResInteger >= 0);
            if (ResPrec - ResInteger < ResScale)
                ResScale = ResPrec - ResInteger;

            // Adjust both operands to be the same scale as ResScale.
            if (MyScale != ResScale)
                x.AdjustScale(ResScale - MyScale, true);

            if (OpScale != ResScale)
                y.AdjustScale(ResScale - OpScale, true);

            // When sign of first operand is negative
            // negate all operands including result.
            if (!fMySignPos)
            {
                fMySignPos = !fMySignPos;
                fOpSignPos = !fOpSignPos;
                fResSignPos = !fResSignPos;
            }

            // Initialize operand lengths and pointer.
            culOp1 = x.m_bLen;
            culOp2 = y.m_bLen;

            uint[] rglData1 = new uint[4] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 };
            uint[] rglData2 = new uint[4] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 };

            if (fOpSignPos)
            {
                dwlAccum = 0;

                // CONSIDER: Call AddUlong when possible

                // Loop through UI4s adding operands and putting result in *this
                // of the operands and put result in *this
                for (iulData = 0; iulData < culOp1 || iulData < culOp2; iulData++)
                {
                    // None of these DWORDLONG additions can overflow, as dwlAccum comes in < x_lInt32Base
                    if (iulData < culOp1)
                        dwlAccum += rglData1[iulData];
                    if (iulData < culOp2)
                        dwlAccum += rglData2[iulData];

                    rglData1[iulData] = (uint)dwlAccum; // equiv to mod x_lInt32Base
                    dwlAccum >>= 32; // equiv to div x_lInt32Base
                }

                //If carry
                if (dwlAccum != 0)
                {
                    Debug.Assert(dwlAccum < s_ulInt32Base);

                    //Either overflowed
                    if (iulData == s_cNumeMax)
                        throw new OverflowException(SQLResource.ArithOverflowMessage);

                    // Or extended length
                    rglData1[iulData] = (uint)dwlAccum;
                    iulData++;
                }

                // Set result length
                bLen = (byte)iulData;
            }
            else
            {
                int iulLastNonZero = 0; // The last nonzero UI

                // When second operand is negative, switch operands
                // if operand2 is greater than operand1
                if (x.LAbsCmp(y) < 0)
                {
                    fResSignPos = !fResSignPos;
                    uint[] rguiTemp = rglData2;
                    rglData2 = rglData1;
                    rglData1 = rguiTemp;
                    culOp1 = culOp2;
                    culOp2 = x.m_bLen;
                }

                dwlAccum = s_ulInt32Base;
                for (iulData = 0; iulData < culOp1 || iulData < culOp2; iulData++)
                {
                    if (iulData < culOp1)
                        dwlAccum += rglData1[iulData];
                    if (iulData < culOp2)
                        dwlAccum -= rglData2[iulData];

                    rglData1[iulData] = (uint)dwlAccum; // equiv to mod BaseUI4
                    if (rglData1[iulData] != 0)
                        iulLastNonZero = iulData;
                    dwlAccum >>= 32; // equiv to /= BaseUI4
                    dwlAccum += s_ulInt32BaseForMod; // equiv to BaseUI4 - 1
                }
                // Set length based on highest non-zero ULONG
                bLen = (byte)(iulLastNonZero + 1);
            }

            SqlDecimal ret = new SqlDecimal(rglData1, bLen, (byte)ResPrec, (byte)ResScale, fResSignPos);

            if (ret.FGt10_38() || ret.CalculatePrecision() > s_NUMERIC_MAX_PRECISION)
                throw new OverflowException(SQLResource.ArithOverflowMessage);

            if (ret.FZero())
                ret.SetPositive();

            ret.AssertValid();

            return ret;
        }
 public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y)
 {
     int num;
     ulong num2;
     byte num11;
     if (x.IsNull || y.IsNull)
     {
         return Null;
     }
     bool fPositive = true;
     bool isPositive = x.IsPositive;
     bool flag2 = y.IsPositive;
     int bScale = x.m_bScale;
     int num7 = y.m_bScale;
     int num9 = Math.Max((int) (x.m_bPrec - bScale), (int) (y.m_bPrec - num7));
     int num3 = Math.Max(bScale, num7);
     int num6 = (num9 + num3) + 1;
     num6 = Math.Min(MaxPrecision, num6);
     if ((num6 - num9) < num3)
     {
         num3 = num6 - num9;
     }
     if (bScale != num3)
     {
         x.AdjustScale(num3 - bScale, true);
     }
     if (num7 != num3)
     {
         y.AdjustScale(num3 - num7, true);
     }
     if (!isPositive)
     {
         isPositive = !isPositive;
         flag2 = !flag2;
         fPositive = !fPositive;
     }
     int bLen = x.m_bLen;
     int num4 = y.m_bLen;
     uint[] rglData = new uint[] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 };
     uint[] numArray4 = new uint[] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 };
     if (flag2)
     {
         num2 = 0L;
         num = 0;
         while ((num < bLen) || (num < num4))
         {
             if (num < bLen)
             {
                 num2 += rglData[num];
             }
             if (num < num4)
             {
                 num2 += numArray4[num];
             }
             rglData[num] = (uint) num2;
             num2 = num2 >> 0x20;
             num++;
         }
         if (num2 != 0L)
         {
             if (num == x_cNumeMax)
             {
                 throw new OverflowException(SQLResource.ArithOverflowMessage);
             }
             rglData[num] = (uint) num2;
             num++;
         }
         num11 = (byte) num;
     }
     else
     {
         int num10 = 0;
         if (x.LAbsCmp(y) < 0)
         {
             fPositive = !fPositive;
             uint[] numArray5 = numArray4;
             numArray4 = rglData;
             rglData = numArray5;
             bLen = num4;
             num4 = x.m_bLen;
         }
         num2 = x_ulInt32Base;
         for (num = 0; (num < bLen) || (num < num4); num++)
         {
             if (num < bLen)
             {
                 num2 += rglData[num];
             }
             if (num < num4)
             {
                 num2 -= numArray4[num];
             }
             rglData[num] = (uint) num2;
             if (rglData[num] != 0)
             {
                 num10 = num;
             }
             num2 = num2 >> 0x20;
             num2 += x_ulInt32BaseForMod;
         }
         num11 = (byte) (num10 + 1);
     }
     SqlDecimal num12 = new SqlDecimal(rglData, num11, (byte) num6, (byte) num3, fPositive);
     if (num12.FGt10_38() || (num12.CalculatePrecision() > NUMERIC_MAX_PRECISION))
     {
         throw new OverflowException(SQLResource.ArithOverflowMessage);
     }
     if (num12.FZero())
     {
         num12.SetPositive();
     }
     return num12;
 }
 private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate)
 {
     if (n.IsNull)
     {
         return Null;
     }
     if (lPosition >= 0)
     {
         lPosition = Math.Min(NUMERIC_MAX_PRECISION, lPosition);
         if (lPosition >= n.m_bScale)
         {
             return n;
         }
     }
     else
     {
         lPosition = Math.Max(-NUMERIC_MAX_PRECISION, lPosition);
         if (lPosition < (n.m_bScale - n.m_bPrec))
         {
             n.SetToZero();
             return n;
         }
     }
     uint num2 = 0;
     int num = Math.Abs((int) (lPosition - n.m_bScale));
     uint num3 = 1;
     while (num > 0)
     {
         if (num >= 9)
         {
             num2 = n.DivByULong(x_rgulShiftBase[8]);
             num3 = x_rgulShiftBase[8];
             num -= 9;
         }
         else
         {
             num2 = n.DivByULong(x_rgulShiftBase[num - 1]);
             num3 = x_rgulShiftBase[num - 1];
             num = 0;
         }
     }
     if (num3 > 1)
     {
         num2 /= num3 / 10;
     }
     if (n.FZero() && (fTruncate || (num2 < 5)))
     {
         n.SetPositive();
         return n;
     }
     if ((num2 >= 5) && !fTruncate)
     {
         n.AddULong(1);
     }
     num = Math.Abs((int) (lPosition - n.m_bScale));
     while (num-- > 0)
     {
         n.MultByULong(x_ulBase10);
     }
     return n;
 }
 public static SqlDecimal Floor(SqlDecimal n)
 {
     if (n.IsNull)
     {
         return Null;
     }
     if (n.m_bScale != 0)
     {
         bool flag;
         n.MakeInteger(out flag);
         if (flag && !n.IsPositive)
         {
             n.AddULong(1);
         }
         if (n.FZero())
         {
             n.SetPositive();
         }
     }
     return n;
 }
 public static SqlDecimal Abs(SqlDecimal n)
 {
     if (n.IsNull)
     {
         return Null;
     }
     n.SetPositive();
     return n;
 }
 public static SqlDecimal operator /(SqlDecimal x, SqlDecimal y)
 {
     int num4;
     int num8;
     if (x.IsNull || y.IsNull)
     {
         return Null;
     }
     if (y.FZero())
     {
         throw new DivideByZeroException(SQLResource.DivideByZeroMessage);
     }
     bool fPositive = x.IsPositive == y.IsPositive;
     int num = Math.Max((x.m_bScale + y.m_bPrec) + 1, (int) x_cNumeDivScaleMin);
     int num3 = (x.m_bPrec - x.m_bScale) + y.m_bScale;
     int num2 = ((num + x.m_bPrec) + y.m_bPrec) + 1;
     int num7 = Math.Min(num, x_cNumeDivScaleMin);
     num3 = Math.Min(num3, NUMERIC_MAX_PRECISION);
     num2 = num3 + num;
     if (num2 > NUMERIC_MAX_PRECISION)
     {
         num2 = NUMERIC_MAX_PRECISION;
     }
     num = Math.Max(Math.Min(num2 - num3, num), num7);
     int digits = (num - x.m_bScale) + y.m_bScale;
     x.AdjustScale(digits, true);
     uint[] rgulU = new uint[] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 };
     uint[] rgulD = new uint[] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 };
     uint[] rgulR = new uint[x_cNumeMax + 1];
     uint[] rgulQ = new uint[x_cNumeMax];
     MpDiv(rgulU, x.m_bLen, rgulD, y.m_bLen, rgulQ, out num4, rgulR, out num8);
     ZeroToMaxLen(rgulQ, num4);
     SqlDecimal num5 = new SqlDecimal(rgulQ, (byte) num4, (byte) num2, (byte) num, fPositive);
     if (num5.FZero())
     {
         num5.SetPositive();
     }
     return num5;
 }