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

CalculatePrecision() private method

private CalculatePrecision ( ) : byte
return byte
        private byte CalculatePrecision()
        {
            int tableIndex;
            byte precision;
            uint[] decimalHelpers;
            uint decimalPart;

            if (_data4 != 0)
            {
                tableIndex = HelperTableStartIndexHiHi;
                decimalHelpers = s_decimalHelpersHiHi;
                decimalPart = _data4;
            }
            else if (_data3 != 0)
            {
                tableIndex = HelperTableStartIndexHi;
                decimalHelpers = s_decimalHelpersHi;
                decimalPart = _data3;
            }
            else if (_data2 != 0)
            {
                tableIndex = HelperTableStartIndexMid;
                decimalHelpers = s_decimalHelpersMid;
                decimalPart = _data2;
            }
            else
            {
                tableIndex = HelperTableStartIndexLo;
                decimalHelpers = s_decimalHelpersLo;
                decimalPart = _data1;
            }


            // this code will move the index no more than -2 -2 -1 (-5) or +2 +1 +1 (+4)
            // from the initial position
            //
            if (decimalPart < decimalHelpers[tableIndex])
            {
                tableIndex -= 2;
                if (decimalPart < decimalHelpers[tableIndex])
                {
                    tableIndex -= 2;
                    if (decimalPart < decimalHelpers[tableIndex])
                    {
                        tableIndex -= 1;
                    }
                    else
                    {
                        tableIndex += 1;
                    }
                }
                else
                {
                    tableIndex += 1;
                }
            }
            else
            {
                tableIndex += 2;
                if (decimalPart < decimalHelpers[tableIndex])
                {
                    tableIndex -= 1;
                }
                else
                {
                    tableIndex += 1;
                }
            }
            if (decimalPart >= decimalHelpers[tableIndex])
            {
                tableIndex += 1;
                if (tableIndex == 37 && decimalPart >= decimalHelpers[tableIndex])
                {
                    // This can happen only if the actual value is greater than 1E+38,
                    // in which case, tableIndex starts at 33 and ends at 37.
                    // Note that in this case, the actual value will be out of SqlDeicmal's range,
                    // and tableIndex is out of the array boudary. We'll throw later in ctors.
                    tableIndex += 1;
                }
            }

            precision = (byte)(tableIndex + 1);
            if (precision > 1)
            {
                // not done yet
                // tableIndex may still be off by one since we didn't look at the lower words
                //
                if (VerifyPrecision((byte)(precision - 1)))
                {
                    precision -= 1;
                }
            }
            Debug.Assert((precision == MaxPrecision + 1) || VerifyPrecision(precision), "Calcualted precision too low?");
            Debug.Assert((precision == 1) || !VerifyPrecision((byte)(precision - 1)), "Calculated precision too high?");

            // adjust the precision
            // This might not be correct but is to our best knowledge
            precision = Math.Max(precision, _bScale);
#if DEBUG
            byte bPrec = _bPrec;   // store current value
            _bPrec = MaxPrecision; // BActualPrec does not work if m_bPrec uninitialized!
            byte bActualPrecision = BActualPrec();
            _bPrec = bPrec;  // restore current value

            Debug.Assert(precision == bActualPrecision, string.Format(null, "CalculatePrecision={0}, BActualPrec={1}. Results must be equal!", precision, bActualPrecision));
#endif
            return precision;
        }

Usage Example

Example #1
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;
        }
All Usage Examples Of System.Data.SqlTypes.SqlDecimal::CalculatePrecision