public static BigDecimal DivideToIntegralValue(BigDecimal dividend, BigDecimal divisor, MathContext mc)
        {
            int        mcPrecision   = mc.Precision;
            int        diffPrecision = dividend.Precision - divisor.Precision;
            int        lastPow       = BigDecimal.TenPow.Length - 1;
            long       diffScale     = (long)dividend.Scale - divisor.Scale;
            long       newScale      = diffScale;
            long       quotPrecision = diffPrecision - diffScale + 1;
            BigInteger quotient;
            BigInteger remainder;

            // In special cases it call the dual method
            if ((mcPrecision == 0) || (dividend.IsZero) || (divisor.IsZero))
            {
                return(DivideToIntegralValue(dividend, divisor));
            }
            // Let be:   this = [u1,s1]   and   divisor = [u2,s2]
            if (quotPrecision <= 0)
            {
                quotient = BigInteger.Zero;
            }
            else if (diffScale == 0)
            {
                // CASE s1 == s2:  to calculate   u1 / u2
                quotient = dividend.UnscaledValue / divisor.UnscaledValue;
            }
            else if (diffScale > 0)
            {
                // CASE s1 >= s2:  to calculate   u1 / (u2 * 10^(s1-s2)
                quotient = dividend.UnscaledValue / (divisor.UnscaledValue * Multiplication.PowerOf10(diffScale));
                // To chose  10^newScale  to get a quotient with at least 'mc.precision()' digits
                newScale = System.Math.Min(diffScale, System.Math.Max(mcPrecision - quotPrecision + 1, 0));
                // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale
                quotient = quotient * Multiplication.PowerOf10(newScale);
            }
            else
            {
                // CASE s2 > s1:

                /* To calculate the minimum power of ten, such that the quotient
                 *   (u1 * 10^exp) / u2   has at least 'mc.precision()' digits. */
                long exp = System.Math.Min(-diffScale, System.Math.Max((long)mcPrecision - diffPrecision, 0));
                long compRemDiv;
                // Let be:   (u1 * 10^exp) / u2 = [q,r]
                quotient = BigMath.DivideAndRemainder(dividend.UnscaledValue * Multiplication.PowerOf10(exp),
                                                      divisor.UnscaledValue, out remainder);
                newScale += exp;                 // To fix the scale
                exp       = -newScale;           // The remaining power of ten
                // If after division there is a remainder...
                if ((remainder.Sign != 0) && (exp > 0))
                {
                    // Log10(r) + ((s2 - s1) - exp) > mc.precision ?
                    compRemDiv = (new BigDecimal(remainder)).Precision
                                 + exp - divisor.Precision;
                    if (compRemDiv == 0)
                    {
                        // To calculate:  (r * 10^exp2) / u2
                        remainder  = (remainder * Multiplication.PowerOf10(exp)) / divisor.UnscaledValue;
                        compRemDiv = System.Math.Abs(remainder.Sign);
                    }
                    if (compRemDiv > 0)
                    {
                        // The quotient won't fit in 'mc.precision()' digits
                        // math.06=Division impossible
                        throw new ArithmeticException(Messages.math06);                         //$NON-NLS-1$
                    }
                }
            }
            // Fast return if the quotient is zero
            if (quotient.Sign == 0)
            {
                return(BigDecimal.GetZeroScaledBy(diffScale));
            }
            BigInteger strippedBI      = quotient;
            BigDecimal integralValue   = new BigDecimal(quotient);
            long       resultPrecision = integralValue.Precision;
            int        i = 1;

            // To strip trailing zeros until the specified precision is reached
            while (!BigInteger.TestBit(strippedBI, 0))
            {
                quotient = BigMath.DivideAndRemainder(strippedBI, BigDecimal.TenPow[i], out remainder);
                if ((remainder.Sign == 0) &&
                    ((resultPrecision - i >= mcPrecision) ||
                     (newScale - i >= diffScale)))
                {
                    resultPrecision -= i;
                    newScale        -= i;
                    if (i < lastPow)
                    {
                        i++;
                    }
                    strippedBI = quotient;
                }
                else
                {
                    if (i == 1)
                    {
                        break;
                    }
                    i = 1;
                }
            }
            // To check if the result fit in 'mc.precision()' digits
            if (resultPrecision > mcPrecision)
            {
                // math.06=Division impossible
                throw new ArithmeticException(Messages.math06);                 //$NON-NLS-1$
            }
            integralValue.Scale = BigDecimal.ToIntScale(newScale);
            integralValue.SetUnscaledValue(strippedBI);
            return(integralValue);
        }
        public static bool TryParse(char[] inData, int offset, int len, IFormatProvider provider, out BigDecimal value,
                                    out Exception exception)
        {
            if (inData == null || inData.Length == 0)
            {
                exception = new FormatException("Cannot parse an empty string.");
                value     = null;
                return(false);
            }

            var numberformatInfo = provider.GetFormat(typeof(NumberFormatInfo)) as NumberFormatInfo;

            if (numberformatInfo == null)
            {
                numberformatInfo = NumberFormatInfo.CurrentInfo;
            }

            var decSep = numberformatInfo.NumberDecimalSeparator;

            if (decSep.Length > 1)
            {
                exception = new NotSupportedException("More than one decimal separator not yet supported");
                value     = null;
                return(false);
            }

            var cDecSep = decSep[0];

            int begin = offset;             // first index to be copied
            int last  = offset + (len - 1); // last index to be copied

            if ((last >= inData.Length) || (offset < 0) || (len <= 0) || (last < 0))
            {
                exception = new FormatException();
                value     = null;
                return(false);
            }

            var v = new BigDecimal();

            try {
                var unscaledBuffer = new StringBuilder(len);
                int bufLength      = 0;
                // To skip a possible '+' symbol
                if ((offset <= last) && (inData[offset] == '+'))
                {
                    offset++;
                    begin++;
                }

                int  counter    = 0;
                bool wasNonZero = false;
                // Accumulating all digits until a possible decimal point
                for (;
                     (offset <= last) &&
                     (inData[offset] != cDecSep) &&
                     (inData[offset] != 'e') &&
                     (inData[offset] != 'E');
                     offset++)
                {
                    if (!wasNonZero)
                    {
                        if (inData[offset] == '0')
                        {
                            counter++;
                        }
                        else
                        {
                            wasNonZero = true;
                        }
                    }
                }

                unscaledBuffer.Append(inData, begin, offset - begin);
                bufLength += offset - begin;
                // A decimal point was found
                if ((offset <= last) && (inData[offset] == cDecSep))
                {
                    offset++;
                    // Accumulating all digits until a possible exponent
                    begin = offset;
                    for (;
                         (offset <= last) &&
                         (inData[offset] != 'e') &&
                         (inData[offset] != 'E');
                         offset++)
                    {
                        if (!wasNonZero)
                        {
                            if (inData[offset] == '0')
                            {
                                counter++;
                            }
                            else
                            {
                                wasNonZero = true;
                            }
                        }
                    }

                    v.Scale    = offset - begin;
                    bufLength += v.Scale;
                    unscaledBuffer.Append(inData, begin, v.Scale);
                }
                else
                {
                    v.Scale = 0;
                }
                // An exponent was found
                if ((offset <= last) && ((inData[offset] == 'e') || (inData[offset] == 'E')))
                {
                    offset++;
                    // Checking for a possible sign of scale
                    begin = offset;
                    if ((offset <= last) && (inData[offset] == '+'))
                    {
                        offset++;
                        if ((offset <= last) && (inData[offset] != '-'))
                        {
                            begin++;
                        }
                    }

                    // Accumulating all remaining digits
                    string scaleString = new String(inData, begin, last + 1 - begin);                     // buffer for scale
                    // Checking if the scale is defined
                    long newScale = (long)v.Scale - Int32.Parse(scaleString, provider);                   // the new scale
                    v.Scale = (int)newScale;
                    if (newScale != v.Scale)
                    {
                        // math.02=Scale out of range.
                        throw new FormatException(Messages.math02);                         //$NON-NLS-1$
                    }
                }

                // Parsing the unscaled value
                if (bufLength < 19)
                {
                    long smallValue;
                    if (!Int64.TryParse(unscaledBuffer.ToString(), NumberStyles.Integer, provider, out smallValue))
                    {
                        value     = null;
                        exception = new FormatException();
                        return(false);
                    }

                    v.SmallValue = smallValue;
                    v.BitLength  = BigDecimal.CalcBitLength(v.SmallValue);
                }
                else
                {
                    v.SetUnscaledValue(BigInteger.Parse(unscaledBuffer.ToString()));
                }

                v.Precision = unscaledBuffer.Length - counter;
                if (unscaledBuffer[0] == '-')
                {
                    v.Precision--;
                }

                value     = v;
                exception = null;
                return(true);
            } catch (Exception ex) {
                exception = ex;
                value     = null;
                return(false);
            }
        }