internal static void FormatBigInteger(ref ValueStringBuilder sb, int precision, int scale, bool sign, ReadOnlySpan <char> format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
        {
            unsafe
            {
                fixed(char *overrideDigits = digits)
                {
                    var numberBuffer = new Number.NumberBuffer();

                    numberBuffer.overrideDigits = overrideDigits + startIndex;
                    numberBuffer.precision      = precision;
                    numberBuffer.scale          = scale;
                    numberBuffer.sign           = sign;

                    char fmt = Number.ParseFormatSpecifier(format, out int maxDigits);

                    if (fmt != 0)
                    {
                        Number.NumberToString(ref sb, ref numberBuffer, fmt, maxDigits, numberFormatInfo, isDecimal: false);
                    }
                    else
                    {
                        Number.NumberToStringFormat(ref sb, ref numberBuffer, format, numberFormatInfo);
                    }
                }
            }
        }
Esempio n. 2
0
                // System.Number
                internal unsafe static bool TryParseInt32(string s, NumberStyles style, NumberFormatInfo info, out int result)
                {
                    byte *stackBuffer = stackalloc byte[1 * 114 / 1];

                    Number.NumberBuffer numberBuffer = new Number.NumberBuffer(stackBuffer);
                    result = 0;
                    if (!Number.TryStringToNumber(s, style, ref numberBuffer, info, false))
                    {
                        return(false);
                    }
                    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
                    {
                        if (!Number.HexNumberToInt32(ref numberBuffer, ref result))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        if (!Number.NumberToInt32(ref numberBuffer, ref result))
                        {
                            return(false);
                        }
                    }
                    return(true);
Esempio n. 3
0
        internal static unsafe bool TryParseBigInteger(string value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
        {
            ArgumentException exception;

            result = BigInteger.Zero;
            if (!TryValidateParseStyleInteger(style, out exception))
            {
                throw exception;
            }
            BigNumberBuffer number      = BigNumberBuffer.Create();
            byte *          stackBuffer = stackalloc byte[0x72];

            Number.NumberBuffer buffer2 = new Number.NumberBuffer(stackBuffer);
            result = 0;
            if (!Number.TryStringToNumber(value, style, ref buffer2, number.digits, info, false))
            {
                return(false);
            }
            number.precision = buffer2.precision;
            number.scale     = buffer2.scale;
            number.sign      = buffer2.sign;
            if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
            {
                if (!HexNumberToBigInteger(ref number, ref result))
                {
                    return(false);
                }
            }
            else if (!NumberToBigInteger(ref number, ref result))
            {
                return(false);
            }
            return(true);
        }
Esempio n. 4
0
        /// <summary>
        /// Parses a Decimal at the start of a Utf8 string.
        /// </summary>
        /// <param name="source">The Utf8 string to parse</param>
        /// <param name="value">Receives the parsed value</param>
        /// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
        /// <param name="standardFormat">Expected format of the Utf8 string</param>
        /// <returns>
        /// true for success. "bytesConsumed" contains the length in bytes of the substring that was parsed.
        /// false if the string was not syntactically valid or an overflow or underflow occurred. "bytesConsumed" is set to 0.
        /// </returns>
        /// <remarks>
        /// Formats supported:
        ///     G/g  (default)
        ///     F/f             12.45       Fixed point
        ///     E/e             1.245000e1  Exponential
        /// </remarks>
        /// <exceptions>
        /// <cref>System.FormatException</cref> if the format is not valid for this data type.
        /// </exceptions>
        public static unsafe bool TryParse(ReadOnlySpan <byte> source, out decimal value, out int bytesConsumed, char standardFormat = default)
        {
            ParseNumberOptions options;

            switch (standardFormat)
            {
            case default(char):
            case 'G':
            case 'g':
            case 'E':
            case 'e':
                options = ParseNumberOptions.AllowExponent;
                break;

            case 'F':
            case 'f':
                options = default;
                break;

            default:
                return(ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed));
            }

            byte *pDigits = stackalloc byte[Number.DecimalNumberBufferLength];

            Number.NumberBuffer number = new Number.NumberBuffer(Number.NumberBufferKind.Decimal, pDigits, Number.DecimalNumberBufferLength);

            if (!TryParseNumber(source, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
            {
                value = default;
                return(false);
            }

            if ((!textUsedExponentNotation) && (standardFormat == 'E' || standardFormat == 'e'))
            {
                value         = default;
                bytesConsumed = 0;
                return(false);
            }

            // More compat with .NET behavior - whether or not a 0 keeps the negative sign depends on whether it an "integer" 0 or a "fractional" 0
            if (number.Digits[0] == 0 && number.Scale == 0)
            {
                number.IsNegative = false;
            }

            value = default;
            if (!Number.TryNumberToDecimal(ref number, ref value))
            {
                value         = default;
                bytesConsumed = 0;
                return(false);
            }

            return(true);
        }
Esempio n. 5
0
        public static unsafe bool TryParse(ReadOnlySpan <byte> source, out decimal value, out int bytesConsumed, char standardFormat = default)
        {
            ParseNumberOptions options;

            switch (standardFormat)
            {
            case default(char):
            case 'G':
            case 'g':
            case 'E':
            case 'e':
                options = ParseNumberOptions.AllowExponent;
                break;

            case 'F':
            case 'f':
                options = default;
                break;

            default:
                return(ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed));
            }

            byte *pDigits = stackalloc byte[Number.DecimalNumberBufferLength];

            Number.NumberBuffer number = new Number.NumberBuffer(Number.NumberBufferKind.Decimal, pDigits, Number.DecimalNumberBufferLength);

            if (!TryParseNumber(source, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
            {
                value = default;
                return(false);
            }

            if ((!textUsedExponentNotation) && (standardFormat == 'E' || standardFormat == 'e'))
            {
                value         = default;
                bytesConsumed = 0;
                return(false);
            }

            value = default;

            if (!Number.TryNumberToDecimal(ref number, ref value))
            {
                value         = default;
                bytesConsumed = 0;
                return(false);
            }

            return(true);
        }
Esempio n. 6
0
        public static unsafe bool TryParse(ReadOnlySpan <byte> source, out double value, out int bytesConsumed, char standardFormat = default)
        {
            byte *pDigits = stackalloc byte[Number.DoubleNumberBufferLength];

            Number.NumberBuffer number = new Number.NumberBuffer(Number.NumberBufferKind.FloatingPoint, pDigits, Number.DoubleNumberBufferLength);

            if (TryParseNormalAsFloatingPoint(source, ref number, out bytesConsumed, standardFormat))
            {
                value = Number.NumberToDouble(ref number);
                return(true);
            }

            return(TryParseAsSpecialFloatingPoint(source, double.PositiveInfinity, double.NegativeInfinity, double.NaN, out value, out bytesConsumed));
        }
        internal static string FormatBigInteger(int precision, int scale, bool sign, string format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
        {
            unsafe
            {
                int  maxDigits;
                char fmt = Number.ParseFormatSpecifier(format, out maxDigits);

                fixed(char *overrideDigits = digits)
                {
                    Number.NumberBuffer numberBuffer = new Number.NumberBuffer();
                    numberBuffer.overrideDigits = overrideDigits + startIndex;
                    numberBuffer.precision      = precision;
                    numberBuffer.scale          = scale;
                    numberBuffer.sign           = sign;
                    if (fmt != 0)
                    {
                        return(Number.NumberToString(numberBuffer, fmt, maxDigits, numberFormatInfo, isDecimal: false));
                    }
                    return(Number.NumberToStringFormat(numberBuffer, format, numberFormatInfo));
                }
            }
        }
Esempio n. 8
0
        internal unsafe static Boolean TryParseBigInteger(String value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
        {
            result = BigInteger.Zero;
            ArgumentException e;

            if (!TryValidateParseStyleInteger(style, out e))
            {
                throw e; // TryParse still throws ArgumentException on invalid NumberStyles
            }
            BigNumberBuffer bignumber         = BigNumberBuffer.Create();
            Byte *          numberBufferBytes = stackalloc Byte[Number.NumberBuffer.NumberBufferBytes];

            Number.NumberBuffer number = new Number.NumberBuffer(numberBufferBytes);
            result = 0;

            if (!Number.TryStringToNumber(value, style, ref number, bignumber.digits, info, false))
            {
                return(false);
            }
            bignumber.precision = number.precision;
            bignumber.scale     = number.scale;
            bignumber.sign      = number.sign;

            if ((style & NumberStyles.AllowHexSpecifier) != 0)
            {
                if (!HexNumberToBigInteger(ref bignumber, ref result))
                {
                    return(false);
                }
            }
            else
            {
                if (!NumberToBigInteger(ref bignumber, ref result))
                {
                    return(false);
                }
            }
            return(true);
        }
Esempio n. 9
0
        static String FormatBigInteger(BigInteger value, String format, NumberFormatInfo info)
        {
            int  digits = 0;
            char fmt    = ParseFormatSpecifier(format, out digits);

            if (fmt == 'x' || fmt == 'X')
            {
                return(FormatBigIntegerToHexString(value, fmt, digits, info));
            }

            bool decimalFmt = (fmt == 'g' || fmt == 'G' || fmt == 'd' || fmt == 'D' || fmt == 'r' || fmt == 'R');

#if SILVERLIGHT || FEATURE_NETCORE || MONO
            if (!decimalFmt)
            {
                // Silverlight supports invariant formats only
                throw new FormatException(SR.GetString(SR.Format_InvalidFormatSpecifier));
            }
#endif //SILVERLIGHT ||FEATURE_NETCORE || MONO

            if (value._bits == null)
            {
                if (fmt == 'g' || fmt == 'G' || fmt == 'r' || fmt == 'R')
                {
                    if (digits > 0)
                    {
                        format = String.Format(CultureInfo.InvariantCulture, "D{0}", digits.ToString(CultureInfo.InvariantCulture));
                    }
                    else
                    {
                        format = "D";
                    }
                }
                return(value._sign.ToString(format, info));
            }


            // First convert to base 10^9.
            const uint kuBase   = 1000000000; // 10^9
            const int  kcchBase = 9;

            int cuSrc = BigInteger.Length(value._bits);
            int cuMax;
            try {
                cuMax = checked (cuSrc * 10 / 9 + 2);
            }
            catch (OverflowException e) { throw new FormatException(SR.GetString(SR.Format_TooLarge), e); }
            uint[] rguDst = new uint[cuMax];
            int    cuDst  = 0;

            for (int iuSrc = cuSrc; --iuSrc >= 0;)
            {
                uint uCarry = value._bits[iuSrc];
                for (int iuDst = 0; iuDst < cuDst; iuDst++)
                {
                    Contract.Assert(rguDst[iuDst] < kuBase);
                    ulong uuRes = NumericsHelpers.MakeUlong(rguDst[iuDst], uCarry);
                    rguDst[iuDst] = (uint)(uuRes % kuBase);
                    uCarry        = (uint)(uuRes / kuBase);
                }
                if (uCarry != 0)
                {
                    rguDst[cuDst++] = uCarry % kuBase;
                    uCarry         /= kuBase;
                    if (uCarry != 0)
                    {
                        rguDst[cuDst++] = uCarry;
                    }
                }
            }

            int cchMax;
            try {
                // Each uint contributes at most 9 digits to the decimal representation.
                cchMax = checked (cuDst * kcchBase);
            }
            catch (OverflowException e) { throw new FormatException(SR.GetString(SR.Format_TooLarge), e); }

            if (decimalFmt)
            {
                if (digits > 0 && digits > cchMax)
                {
                    cchMax = digits;
                }
                if (value._sign < 0)
                {
                    try {
                        // Leave an extra slot for a minus sign.
                        cchMax = checked (cchMax + info.NegativeSign.Length);
                    }
                    catch (OverflowException e) { throw new FormatException(SR.GetString(SR.Format_TooLarge), e); }
                }
            }

            int rgchBufSize;

            try {
                // We'll pass the rgch buffer to native code, which is going to treat it like a string of digits, so it needs
                // to be null terminated.  Let's ensure that we can allocate a buffer of that size.
                rgchBufSize = checked (cchMax + 1);
            } catch (OverflowException e) { throw new FormatException(SR.GetString(SR.Format_TooLarge), e); }

            char[] rgch = new char[rgchBufSize];

            int ichDst = cchMax;

            for (int iuDst = 0; iuDst < cuDst - 1; iuDst++)
            {
                uint uDig = rguDst[iuDst];
                Contract.Assert(uDig < kuBase);
                for (int cch = kcchBase; --cch >= 0;)
                {
                    rgch[--ichDst] = (char)('0' + uDig % 10);
                    uDig          /= 10;
                }
            }
            for (uint uDig = rguDst[cuDst - 1]; uDig != 0;)
            {
                rgch[--ichDst] = (char)('0' + uDig % 10);
                uDig          /= 10;
            }

#if !SILVERLIGHT || FEATURE_NETCORE
            if (!decimalFmt)
            {
                //
                // Go to the VM for GlobLoc aware formatting
                //
                Byte *numberBufferBytes    = stackalloc Byte[Number.NumberBuffer.NumberBufferBytes];
                Number.NumberBuffer number = new Number.NumberBuffer(numberBufferBytes);
                // sign = true for negative and false for 0 and positive values
                number.sign = (value._sign < 0);
                // the cut-off point to switch (G)eneral from (F)ixed-point to (E)xponential form
                number.precision = 29;
                number.digits[0] = '\0';
                number.scale     = cchMax - ichDst;

                int maxDigits = Math.Min(ichDst + 50, cchMax);
                for (int i = ichDst; i < maxDigits; i++)
                {
                    number.digits[i - ichDst] = rgch[i];
                }

                fixed(char *pinnedExtraDigits = rgch)
                {
                    return(Number.FormatNumberBuffer(number.PackForNative(), format, info, pinnedExtraDigits + ichDst));
                }
            }
#endif //!SILVERLIGHT ||FEATURE_NETCORE

            // Format Round-trip decimal
            // This format is supported for integral types only. The number is converted to a string of
            // decimal digits (0-9), prefixed by a minus sign if the number is negative. The precision
            // specifier indicates the minimum number of digits desired in the resulting string. If required,
            // the number is padded with zeros to its left to produce the number of digits given by the
            // precision specifier.
            int numDigitsPrinted = cchMax - ichDst;
            while (digits > 0 && digits > numDigitsPrinted)
            {
                // pad leading zeros
                rgch[--ichDst] = '0';
                digits--;
            }
            if (value._sign < 0)
            {
                String negativeSign = info.NegativeSign;
                for (int i = info.NegativeSign.Length - 1; i > -1; i--)
                {
                    rgch[--ichDst] = info.NegativeSign[i];
                }
            }
            return(new String(rgch, ichDst, cchMax - ichDst));
        }
Esempio n. 10
0
        internal static unsafe string FormatBigInteger(BigInteger value, string format, NumberFormatInfo info)
        {
            int  num3;
            int  num9;
            int  digits = 0;
            char ch     = ParseFormatSpecifier(format, out digits);

            switch (ch)
            {
            case 'x':
            case 'X':
                return(FormatBigIntegerToHexString(value, ch, digits, info));
            }
            bool flag = ((((ch == 'g') || (ch == 'G')) || ((ch == 'd') || (ch == 'D'))) || (ch == 'r')) || (ch == 'R');

            if (value._bits == null)
            {
                switch (ch)
                {
                case 'g':
                case 'G':
                case 'r':
                case 'R':
                    if (digits > 0)
                    {
                        format = string.Format(CultureInfo.InvariantCulture, "D{0}", new object[] { digits.ToString(CultureInfo.InvariantCulture) });
                    }
                    else
                    {
                        format = "D";
                    }
                    break;
                }
                return(value._sign.ToString(format, info));
            }
            int num2 = BigInteger.Length(value._bits);

            try
            {
                num3 = ((num2 * 10) / 9) + 2;
            }
            catch (OverflowException exception)
            {
                throw new FormatException(SR.GetString("Format_TooLarge"), exception);
            }
            uint[] numArray = new uint[num3];
            int    num4     = 0;
            int    index    = num2;

            while (--index >= 0)
            {
                uint uLo = value._bits[index];
                for (int k = 0; k < num4; k++)
                {
                    ulong num8 = NumericsHelpers.MakeUlong(numArray[k], uLo);
                    numArray[k] = (uint)(num8 % ((ulong)0x3b9aca00L));
                    uLo         = (uint)(num8 / ((ulong)0x3b9aca00L));
                }
                if (uLo != 0)
                {
                    numArray[num4++] = uLo % 0x3b9aca00;
                    uLo /= 0x3b9aca00;
                    if (uLo != 0)
                    {
                        numArray[num4++] = uLo;
                    }
                }
            }
            try
            {
                num9 = num4 * 9;
            }
            catch (OverflowException exception2)
            {
                throw new FormatException(SR.GetString("Format_TooLarge"), exception2);
            }
            if (flag)
            {
                if ((digits > 0) && (digits > num9))
                {
                    num9 = digits;
                }
                if (value._sign < 0)
                {
                    try
                    {
                        num9 += info.NegativeSign.Length;
                    }
                    catch (OverflowException exception3)
                    {
                        throw new FormatException(SR.GetString("Format_TooLarge"), exception3);
                    }
                }
            }
            char[] chArray    = new char[num9];
            int    startIndex = num9;

            for (int i = 0; i < (num4 - 1); i++)
            {
                uint num12 = numArray[i];
                int  num13 = 9;
                while (--num13 >= 0)
                {
                    chArray[--startIndex] = (char)(0x30 + (num12 % 10));
                    num12 /= 10;
                }
            }
            for (uint j = numArray[num4 - 1]; j != 0; j /= 10)
            {
                chArray[--startIndex] = (char)(0x30 + (j % 10));
            }
            if (!flag)
            {
                byte *stackBuffer          = stackalloc byte[0x72];
                Number.NumberBuffer buffer = new Number.NumberBuffer(stackBuffer)
                {
                    sign      = value._sign < 0,
                    precision = 0x1d
                };
                buffer.digits[0] = '\0';
                buffer.scale     = num9 - startIndex;
                int num15 = Math.Min(startIndex + 50, num9);
                for (int m = startIndex; m < num15; m++)
                {
                    buffer.digits[m - startIndex] = chArray[m];
                }
                return(Number.FormatNumberBuffer(buffer.PackForNative(), format, info));
            }
            int num17 = num9 - startIndex;

            while ((digits > 0) && (digits > num17))
            {
                chArray[--startIndex] = '0';
                digits--;
            }
            if (value._sign < 0)
            {
                string negativeSign = info.NegativeSign;
                for (int n = info.NegativeSign.Length - 1; n > -1; n--)
                {
                    chArray[--startIndex] = info.NegativeSign[n];
                }
            }
            return(new string(chArray, startIndex, num9 - startIndex));
        }
Esempio n. 11
0
        private static bool TryFormatDecimalG(ref Number.NumberBuffer number, Span <byte> destination, out int bytesWritten)
        {
            int scale = number.Scale;
            ReadOnlySpan <byte> digits = number.Digits;
            int numDigits = number.DigitsCount;

            bool isFraction = scale < numDigits;
            int  numBytesNeeded;

            if (isFraction)
            {
                numBytesNeeded = numDigits + 1;  // A fraction. Must include one for the decimal point.
                if (scale <= 0)
                {
                    numBytesNeeded += 1 + (-scale); // A fraction of the form 0.ddd. Need to emit the non-stored 0 before the decimal point plus (-scale) leading 0's after the decimal point.
                }
            }
            else
            {
                numBytesNeeded = ((scale <= 0) ? 1 : scale); // An integral. Just emit the digits before the decimal point (minimum 1) and no decimal point.
            }

            if (number.IsNegative)
            {
                numBytesNeeded++; // And the minus sign.
            }

            if (destination.Length < numBytesNeeded)
            {
                bytesWritten = 0;
                return(false);
            }

            int srcIndex = 0;
            int dstIndex = 0;

            if (number.IsNegative)
            {
                destination[dstIndex++] = Utf8Constants.Minus;
            }

            //
            // Emit digits before the decimal point.
            //
            if (scale <= 0)
            {
                destination[dstIndex++] = (byte)'0';  // The integer portion is 0 and not stored. The formatter, however, needs to emit it.
            }
            else
            {
                while (srcIndex < scale)
                {
                    byte digit = digits[srcIndex];
                    if (digit == 0)
                    {
                        int numTrailingZeroes = scale - srcIndex;
                        for (int i = 0; i < numTrailingZeroes; i++)
                        {
                            destination[dstIndex++] = (byte)'0';
                        }
                        break;
                    }

                    destination[dstIndex++] = digit;
                    srcIndex++;
                }
            }

            if (isFraction)
            {
                destination[dstIndex++] = Utf8Constants.Period;

                //
                // Emit digits after the decimal point.
                //
                if (scale < 0)
                {
                    int numLeadingZeroesToEmit = -scale;
                    for (int i = 0; i < numLeadingZeroesToEmit; i++)
                    {
                        destination[dstIndex++] = (byte)'0';
                    }
                }

                byte digit;
                while ((digit = digits[srcIndex++]) != 0)
                {
                    destination[dstIndex++] = digit;
                }
            }

            Debug.Assert(dstIndex == numBytesNeeded);

            bytesWritten = numBytesNeeded;
            return(true);
        }
Esempio n. 12
0
        private static bool TryParseNormalAsFloatingPoint(ReadOnlySpan <byte> source, ref Number.NumberBuffer number, out int bytesConsumed, char standardFormat)
        {
            ParseNumberOptions options;

            switch (standardFormat)
            {
            case default(char):
            case 'G':
            case 'g':
            case 'E':
            case 'e':
                options = ParseNumberOptions.AllowExponent;
                break;

            case 'F':
            case 'f':
                options = default;
                break;

            default:
                return(ParserHelpers.TryParseThrowFormatException(out bytesConsumed));
            }
            if (!TryParseNumber(source, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
            {
                return(false);
            }
            if ((!textUsedExponentNotation) && (standardFormat == 'E' || standardFormat == 'e'))
            {
                bytesConsumed = 0;
                return(false);
            }
            return(true);
        }
Esempio n. 13
0
                    // System.Number
                    private unsafe static bool TryStringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
                    {
                        if (str == null)
                        {
                            return(false);
                        }

                        fixed(char *ptr = str)
                        {
                            char *ptr2 = ptr;

                            if (!Number.ParseNumber(ref ptr2, options, ref number, numfmt, parseDecimal) || ((ptr2 - ptr / 2) / 2 < str.Length && !Number.TrailingZeros(str, (ptr2 - ptr / 2) / 2)))
                            {
                                return(false);
                            }
                        }

                        return(true);
                    }
Esempio n. 14
0
        private static bool TryFormatDecimalF(ref Number.NumberBuffer number, Span <byte> destination, out int bytesWritten, byte precision)
        {
            int scale = number.Scale;
            ReadOnlySpan <byte> digits = number.Digits;

            int numBytesNeeded =
                ((number.IsNegative) ? 1 : 0)               // minus sign
                + ((scale <= 0) ? 1 : scale)                // digits before the decimal point (minimum 1)
                + ((precision == 0) ? 0 : (precision + 1)); // if specified precision != 0, the decimal point and the digits after the decimal point (padded with zeroes if needed)

            if (destination.Length < numBytesNeeded)
            {
                bytesWritten = 0;
                return(false);
            }

            int srcIndex = 0;
            int dstIndex = 0;

            if (number.IsNegative)
            {
                destination[dstIndex++] = Utf8Constants.Minus;
            }

            //
            // Emit digits before the decimal point.
            //
            if (scale <= 0)
            {
                destination[dstIndex++] = (byte)'0';  // The integer portion is 0 and not stored. The formatter, however, needs to emit it.
            }
            else
            {
                while (srcIndex < scale)
                {
                    byte digit = digits[srcIndex];
                    if (digit == 0)
                    {
                        int numTrailingZeroes = scale - srcIndex;
                        for (int i = 0; i < numTrailingZeroes; i++)
                        {
                            destination[dstIndex++] = (byte)'0';
                        }
                        break;
                    }

                    destination[dstIndex++] = digit;
                    srcIndex++;
                }
            }

            if (precision > 0)
            {
                destination[dstIndex++] = Utf8Constants.Period;

                //
                // Emit digits after the decimal point.
                //
                int numDigitsEmitted = 0;
                if (scale < 0)
                {
                    int numLeadingZeroesToEmit = Math.Min((int)precision, -scale);
                    for (int i = 0; i < numLeadingZeroesToEmit; i++)
                    {
                        destination[dstIndex++] = (byte)'0';
                    }
                    numDigitsEmitted += numLeadingZeroesToEmit;
                }

                while (numDigitsEmitted < precision)
                {
                    byte digit = digits[srcIndex];
                    if (digit == 0)
                    {
                        while (numDigitsEmitted++ < precision)
                        {
                            destination[dstIndex++] = (byte)'0';
                        }
                        break;
                    }
                    destination[dstIndex++] = digit;
                    srcIndex++;
                    numDigitsEmitted++;
                }
            }

            Debug.Assert(dstIndex == numBytesNeeded);
            bytesWritten = numBytesNeeded;
            return(true);
        }
Esempio n. 15
0
        private static bool TryParseNumber(ReadOnlySpan <byte> source, ref Number.NumberBuffer number, out int bytesConsumed, ParseNumberOptions options, out bool textUsedExponentNotation)
        {
            Debug.Assert(number.DigitsCount == 0);
            Debug.Assert(number.Scale == 0);
            Debug.Assert(number.IsNegative == false);
            Debug.Assert(number.HasNonZeroTail == false);

            number.CheckConsistency();
            textUsedExponentNotation = false;

            if (source.Length == 0)
            {
                bytesConsumed = 0;
                return(false);
            }

            Span <byte> digits = number.Digits;

            int srcIndex = 0;
            int dstIndex = 0;

            // Consume the leading sign if any.
            byte c = source[srcIndex];

            switch (c)
            {
            case Utf8Constants.Minus:
                number.IsNegative = true;
                goto case Utf8Constants.Plus;

            case Utf8Constants.Plus:
                srcIndex++;
                if (srcIndex == source.Length)
                {
                    bytesConsumed = 0;
                    return(false);
                }
                c = source[srcIndex];
                break;

            default:
                break;
            }

            int startIndexDigitsBeforeDecimal = srcIndex;
            int digitCount    = 0;
            int maxDigitCount = digits.Length - 1;

            // Throw away any leading zeroes
            while (srcIndex != source.Length)
            {
                c = source[srcIndex];
                if (c != '0')
                {
                    break;
                }
                srcIndex++;
            }

            if (srcIndex == source.Length)
            {
                bytesConsumed = srcIndex;
                number.CheckConsistency();
                return(true);
            }

            int startIndexNonLeadingDigitsBeforeDecimal = srcIndex;

            int hasNonZeroTail = 0;

            while (srcIndex != source.Length)
            {
                c = source[srcIndex];
                int value = (byte)(c - (byte)('0'));

                if (value > 9)
                {
                    break;
                }

                srcIndex++;
                digitCount++;

                if (digitCount >= maxDigitCount)
                {
                    // For decimal and binary floating-point numbers, we only
                    // need to store digits up to maxDigCount. However, we still
                    // need to keep track of whether any additional digits past
                    // maxDigCount were non-zero, as that can impact rounding
                    // for an input that falls evenly between two representable
                    // results.

                    hasNonZeroTail |= value;
                }
            }
            number.HasNonZeroTail = (hasNonZeroTail != 0);

            int numDigitsBeforeDecimal           = srcIndex - startIndexDigitsBeforeDecimal;
            int numNonLeadingDigitsBeforeDecimal = srcIndex - startIndexNonLeadingDigitsBeforeDecimal;

            Debug.Assert(dstIndex == 0);
            int numNonLeadingDigitsBeforeDecimalToCopy = Math.Min(numNonLeadingDigitsBeforeDecimal, maxDigitCount);

            source.Slice(startIndexNonLeadingDigitsBeforeDecimal, numNonLeadingDigitsBeforeDecimalToCopy).CopyTo(digits);
            dstIndex     = numNonLeadingDigitsBeforeDecimalToCopy;
            number.Scale = numNonLeadingDigitsBeforeDecimal;

            if (srcIndex == source.Length)
            {
                digits[dstIndex]   = 0;
                number.DigitsCount = dstIndex;
                bytesConsumed      = srcIndex;
                number.CheckConsistency();
                return(true);
            }

            int numDigitsAfterDecimal = 0;

            if (c == Utf8Constants.Period)
            {
                //
                // Parse the digits after the decimal point.
                //

                srcIndex++;
                int startIndexDigitsAfterDecimal = srcIndex;

                while (srcIndex != source.Length)
                {
                    c = source[srcIndex];
                    int value = (byte)(c - (byte)('0'));

                    if (value > 9)
                    {
                        break;
                    }

                    srcIndex++;
                    digitCount++;

                    if (digitCount >= maxDigitCount)
                    {
                        // For decimal and binary floating-point numbers, we only
                        // need to store digits up to maxDigCount. However, we still
                        // need to keep track of whether any additional digits past
                        // maxDigCount were non-zero, as that can impact rounding
                        // for an input that falls evenly between two representable
                        // results.

                        hasNonZeroTail |= value;
                    }
                }
                number.HasNonZeroTail = (hasNonZeroTail != 0);

                numDigitsAfterDecimal = srcIndex - startIndexDigitsAfterDecimal;

                int startIndexOfDigitsAfterDecimalToCopy = startIndexDigitsAfterDecimal;
                if (dstIndex == 0)
                {
                    // Not copied any digits to the Number struct yet. This means we must continue discarding leading zeroes even though they appeared after the decimal point.
                    while (startIndexOfDigitsAfterDecimalToCopy < srcIndex && source[startIndexOfDigitsAfterDecimalToCopy] == '0')
                    {
                        number.Scale--;
                        startIndexOfDigitsAfterDecimalToCopy++;
                    }
                }

                int numDigitsAfterDecimalToCopy = Math.Min(srcIndex - startIndexOfDigitsAfterDecimalToCopy, maxDigitCount - dstIndex);
                source.Slice(startIndexOfDigitsAfterDecimalToCopy, numDigitsAfterDecimalToCopy).CopyTo(digits.Slice(dstIndex));
                dstIndex += numDigitsAfterDecimalToCopy;
                // We "should" really NUL terminate, but there are multiple places we'd have to do this and it is a precondition that the caller pass in a fully zero=initialized Number.

                if (srcIndex == source.Length)
                {
                    if (numDigitsBeforeDecimal == 0 && numDigitsAfterDecimal == 0)
                    {
                        // For compatibility. You can say "5." and ".5" but you can't say "."
                        bytesConsumed = 0;
                        return(false);
                    }

                    digits[dstIndex]   = 0;
                    number.DigitsCount = dstIndex;
                    bytesConsumed      = srcIndex;
                    number.CheckConsistency();
                    return(true);
                }
            }

            if (numDigitsBeforeDecimal == 0 && numDigitsAfterDecimal == 0)
            {
                bytesConsumed = 0;
                return(false);
            }

            if ((c & ~0x20u) != 'E')
            {
                digits[dstIndex]   = 0;
                number.DigitsCount = dstIndex;
                bytesConsumed      = srcIndex;
                number.CheckConsistency();
                return(true);
            }

            //
            // Parse the exponent after the "E"
            //
            textUsedExponentNotation = true;
            srcIndex++;

            if ((options & ParseNumberOptions.AllowExponent) == 0)
            {
                bytesConsumed = 0;
                return(false);
            }

            if (srcIndex == source.Length)
            {
                bytesConsumed = 0;
                return(false);
            }

            bool exponentIsNegative = false;

            c = source[srcIndex];
            switch (c)
            {
            case Utf8Constants.Minus:
                exponentIsNegative = true;
                goto case Utf8Constants.Plus;

            case Utf8Constants.Plus:
                srcIndex++;
                if (srcIndex == source.Length)
                {
                    bytesConsumed = 0;
                    return(false);
                }
                c = source[srcIndex];
                break;

            default:
                break;
            }

            // If the next character isn't a digit, an exponent wasn't specified
            if ((byte)(c - (byte)('0')) > 9)
            {
                bytesConsumed = 0;
                return(false);
            }

            if (!TryParseUInt32D(source.Slice(srcIndex), out uint absoluteExponent, out int bytesConsumedByExponent))
            {
                // Since we found at least one digit, we know that any failure to parse means we had an
                // exponent that was larger than uint.MaxValue, and we can just eat characters until the end
                absoluteExponent = uint.MaxValue;

                // This also means that we know there was at least 10 characters and we can "eat" those, and
                // continue eating digits from there
                srcIndex += 10;

                while (srcIndex != source.Length)
                {
                    c = source[srcIndex];
                    int value = (byte)(c - (byte)('0'));

                    if (value > 9)
                    {
                        break;
                    }

                    srcIndex++;
                }
            }

            srcIndex += bytesConsumedByExponent;

            if (exponentIsNegative)
            {
                if (number.Scale < int.MinValue + (long)absoluteExponent)
                {
                    // A scale underflow means all non-zero digits are all so far to the right of the decimal point, no
                    // number format we have will be able to see them. Just pin the scale at the absolute minimum
                    // and let the converter produce a 0 with the max precision available for that type.
                    number.Scale = int.MinValue;
                }
                else
                {
                    number.Scale -= (int)absoluteExponent;
                }
            }
            else
            {
                if (number.Scale > int.MaxValue - (long)absoluteExponent)
                {
                    // A scale overflow means all non-zero digits are all so far to the right of the decimal point, no
                    // number format we have will be able to see them. Just pin the scale at the absolute maximum
                    // and let the converter produce a 0 with the max precision available for that type.
                    number.Scale = int.MaxValue;
                }
                else
                {
                    number.Scale += (int)absoluteExponent;
                }
            }

            digits[dstIndex]   = 0;
            number.DigitsCount = dstIndex;
            bytesConsumed      = srcIndex;
            number.CheckConsistency();
            return(true);
        }
Esempio n. 16
0
        private static bool TryFormatDecimalE(ref Number.NumberBuffer number, Span <byte> destination, out int bytesWritten, byte precision, byte exponentSymbol)
        {
            const int NumExponentDigits = 3;

            int scale = number.Scale;
            ReadOnlySpan <byte> digits = number.Digits;

            int numBytesNeeded =
                ((number.IsNegative) ? 1 : 0)              // minus sign
                + 1                                        // digits before the decimal point (exactly 1)
                + ((precision == 0) ? 0 : (precision + 1)) // period and the digits after the decimal point
                + 2                                        // 'E' or 'e' followed by '+' or '-'
                + NumExponentDigits;                       // exponent digits

            if (destination.Length < numBytesNeeded)
            {
                bytesWritten = 0;
                return(false);
            }

            int dstIndex = 0;
            int srcIndex = 0;

            if (number.IsNegative)
            {
                destination[dstIndex++] = Utf8Constants.Minus;
            }

            //
            // Emit exactly one digit before the decimal point.
            //
            int  exponent;
            byte firstDigit = digits[srcIndex];

            if (firstDigit == 0)
            {
                destination[dstIndex++] = (byte)'0';  // Special case: number before the decimal point is exactly 0: Number does not store the zero in this case.
                exponent = 0;
            }
            else
            {
                destination[dstIndex++] = firstDigit;
                srcIndex++;
                exponent = scale - 1;
            }

            if (precision > 0)
            {
                destination[dstIndex++] = Utf8Constants.Period;

                //
                // Emit digits after the decimal point.
                //
                int numDigitsEmitted = 0;
                while (numDigitsEmitted < precision)
                {
                    byte digit = digits[srcIndex];
                    if (digit == 0)
                    {
                        while (numDigitsEmitted++ < precision)
                        {
                            destination[dstIndex++] = (byte)'0';
                        }
                        break;
                    }
                    destination[dstIndex++] = digit;
                    srcIndex++;
                    numDigitsEmitted++;
                }
            }

            // Emit the exponent symbol
            destination[dstIndex++] = exponentSymbol;
            if (exponent >= 0)
            {
                destination[dstIndex++] = Utf8Constants.Plus;
            }
            else
            {
                destination[dstIndex++] = Utf8Constants.Minus;
                exponent = -exponent;
            }

            Debug.Assert(exponent < Number.DecimalPrecision, "If you're trying to reuse this routine for double/float, you'll need to review the code carefully for Decimal-specific assumptions.");

            // Emit exactly three digits for the exponent.
            destination[dstIndex++] = (byte)'0'; // The exponent for Decimal can never exceed 28 (let alone 99)
            destination[dstIndex++] = (byte)((exponent / 10) + '0');
            destination[dstIndex++] = (byte)((exponent % 10) + '0');

            Debug.Assert(dstIndex == numBytesNeeded);
            bytesWritten = numBytesNeeded;
            return(true);
        }
Esempio n. 17
0
                    // System.Number
                    private unsafe static bool ParseNumber(ref char *str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
                    {
                        number.scale = 0;
                        number.sign  = false;
                        string text  = null;
                        string text2 = null;
                        string str2  = null;
                        string str3  = null;
                        bool   flag  = false;
                        string str4;
                        string str5;

                        if ((options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None)
                        {
                            text = numfmt.CurrencySymbol;
                            if (numfmt.ansiCurrencySymbol != null)
                            {
                                text2 = numfmt.ansiCurrencySymbol;
                            }
                            str2 = numfmt.NumberDecimalSeparator;
                            str3 = numfmt.NumberGroupSeparator;
                            str4 = numfmt.CurrencyDecimalSeparator;
                            str5 = numfmt.CurrencyGroupSeparator;
                            flag = true;
                        }
                        else
                        {
                            str4 = numfmt.NumberDecimalSeparator;
                            str5 = numfmt.NumberGroupSeparator;
                        }
                        int   num = 0;
                        char *ptr = str;
                        char  c   = *ptr;

                        while (true)
                        {
                            if (!Number.IsWhite(c) || (options & NumberStyles.AllowLeadingWhite) == NumberStyles.None || ((num & 1) != 0 && ((num & 1) == 0 || ((num & 32) == 0 && numfmt.numberNegativePattern != 2))))
                            {
                                bool  flag2;
                                char *ptr2;
                                if ((flag2 = ((options & NumberStyles.AllowLeadingSign) != NumberStyles.None && (num & 1) == 0)) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
                                {
                                    num |= 1;
                                    ptr  = ptr2 - (IntPtr)2 / 2;
                                }
                                else
                                {
                                    if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                                    {
                                        num        |= 1;
                                        number.sign = true;
                                        ptr         = ptr2 - (IntPtr)2 / 2;
                                    }
                                    else
                                    {
                                        if (c == '(' && (options & NumberStyles.AllowParentheses) != NumberStyles.None && (num & 1) == 0)
                                        {
                                            num        |= 3;
                                            number.sign = true;
                                        }
                                        else
                                        {
                                            if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                                            {
                                                break;
                                            }
                                            num  |= 32;
                                            text  = null;
                                            text2 = null;
                                            ptr   = ptr2 - (IntPtr)2 / 2;
                                        }
                                    }
                                }
                            }
                            c = *(ptr += (IntPtr)2 / 2);
                        }
                        int num2 = 0;
                        int num3 = 0;

                        while (true)
                        {
                            if ((c >= '0' && c <= '9') || ((options & NumberStyles.AllowHexSpecifier) != NumberStyles.None && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
                            {
                                num |= 4;
                                if (c != '0' || (num & 8) != 0)
                                {
                                    if (num2 < 50)
                                    {
                                        number.digits[(IntPtr)(num2++)] = c;
                                        if (c != '0' || parseDecimal)
                                        {
                                            num3 = num2;
                                        }
                                    }
                                    if ((num & 16) == 0)
                                    {
                                        number.scale++;
                                    }
                                    num |= 8;
                                }
                                else
                                {
                                    if ((num & 16) != 0)
                                    {
                                        number.scale--;
                                    }
                                }
                            }
                            else
                            {
                                char *ptr2;
                                if ((options & NumberStyles.AllowDecimalPoint) != NumberStyles.None && (num & 16) == 0 && ((ptr2 = Number.MatchChars(ptr, str4)) != null || (flag && (num & 32) == 0 && (ptr2 = Number.MatchChars(ptr, str2)) != null)))
                                {
                                    num |= 16;
                                    ptr  = ptr2 - (IntPtr)2 / 2;
                                }
                                else
                                {
                                    if ((options & NumberStyles.AllowThousands) == NumberStyles.None || (num & 4) == 0 || (num & 16) != 0 || ((ptr2 = Number.MatchChars(ptr, str5)) == null && (!flag || (num & 32) != 0 || (ptr2 = Number.MatchChars(ptr, str3)) == null)))
                                    {
                                        break;
                                    }
                                    ptr = ptr2 - (IntPtr)2 / 2;
                                }
                            }
                            c = *(ptr += (IntPtr)2 / 2);
                        }
                        bool flag3 = false;

                        number.precision            = num3;
                        number.digits[(IntPtr)num3] = '\0';
                        if ((num & 4) != 0)
                        {
                            if ((c == 'E' || c == 'e') && (options & NumberStyles.AllowExponent) != NumberStyles.None)
                            {
                                char *ptr3 = ptr;
                                c = *(ptr += (IntPtr)2 / 2);
                                char *ptr2;
                                if ((ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
                                {
                                    c = *(ptr = ptr2);
                                }
                                else
                                {
                                    if ((ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                                    {
                                        c     = *(ptr = ptr2);
                                        flag3 = true;
                                    }
                                }
                                if (c >= '0' && c <= '9')
                                {
                                    int num4 = 0;
                                    do
                                    {
                                        num4 = num4 * 10 + (int)(c - '0');
                                        c    = *(ptr += (IntPtr)2 / 2);
                                        if (num4 > 1000)
                                        {
                                            num4 = 9999;
                                            while (c >= '0' && c <= '9')
                                            {
                                                c = *(ptr += (IntPtr)2 / 2);
                                            }
                                        }
                                    }while (c >= '0' && c <= '9');
                                    if (flag3)
                                    {
                                        num4 = -num4;
                                    }
                                    number.scale += num4;
                                }
                                else
                                {
                                    ptr = ptr3;
                                    c   = *ptr;
                                }
                            }
                            while (true)
                            {
                                if (!Number.IsWhite(c) || (options & NumberStyles.AllowTrailingWhite) == NumberStyles.None)
                                {
                                    bool  flag2;
                                    char *ptr2;
                                    if ((flag2 = ((options & NumberStyles.AllowTrailingSign) != NumberStyles.None && (num & 1) == 0)) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
                                    {
                                        num |= 1;
                                        ptr  = ptr2 - (IntPtr)2 / 2;
                                    }
                                    else
                                    {
                                        if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                                        {
                                            num        |= 1;
                                            number.sign = true;
                                            ptr         = ptr2 - (IntPtr)2 / 2;
                                        }
                                        else
                                        {
                                            if (c == ')' && (num & 2) != 0)
                                            {
                                                num &= -3;
                                            }
                                            else
                                            {
                                                if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                                                {
                                                    break;
                                                }
                                                text  = null;
                                                text2 = null;
                                                ptr   = ptr2 - (IntPtr)2 / 2;
                                            }
                                        }
                                    }
                                }
                                c = *(ptr += (IntPtr)2 / 2);
                            }
                            if ((num & 2) == 0)
                            {
                                if ((num & 8) == 0)
                                {
                                    if (!parseDecimal)
                                    {
                                        number.scale = 0;
                                    }
                                    if ((num & 16) == 0)
                                    {
                                        number.sign = false;
                                    }
                                }
                                str = ptr;
                                return(true);
                            }
                        }
                        str = ptr;
                        return(false);
                    }
        /// <summary>
        /// Formats a Decimal as a UTF8 string.
        /// </summary>
        /// <param name="value">Value to format</param>
        /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
        /// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
        /// <param name="format">The standard format to use</param>
        /// <returns>
        /// true for success. "bytesWritten" contains the length of the formatted text in bytes.
        /// false if buffer was too short. Iteratively increase the size of the buffer and retry until it succeeds.
        /// </returns>
        /// <remarks>
        /// Formats supported:
        ///     G/g  (default)
        ///     F/f             12.45       Fixed point
        ///     E/e             1.245000e1  Exponential
        /// </remarks>
        /// <exceptions>
        /// <cref>System.FormatException</cref> if the format is not valid for this data type.
        /// </exceptions>
        public static unsafe bool TryFormat(decimal value, Span <byte> destination, out int bytesWritten, StandardFormat format = default)
        {
            if (format.IsDefault)
            {
                format = 'G';
            }

            switch (format.Symbol)
            {
            case 'g':
            case 'G':
            {
                if (format.Precision != StandardFormat.NoPrecision)
                {
                    throw new NotSupportedException(SR.Argument_GWithPrecisionNotSupported);
                }

                byte *pDigits = stackalloc byte[Number.DecimalNumberBufferLength];
                Number.NumberBuffer number = new Number.NumberBuffer(Number.NumberBufferKind.Decimal, pDigits, Number.DecimalNumberBufferLength);

                Number.DecimalToNumber(ref value, ref number);
                if (number.Digits[0] == 0)
                {
                    number.IsNegative = false;         // For Decimals, -0 must print as normal 0.
                }
                bool success = TryFormatDecimalG(ref number, destination, out bytesWritten);
#if DEBUG
                // This DEBUG segment exists to close a code coverage hole inside TryFormatDecimalG(). Because we don't call RoundNumber() on this path, we have no way to feed
                // TryFormatDecimalG() a number where trailing zeros before the decimal point have been cropped. So if the chance comes up, we'll crop the zeroes
                // ourselves and make a second call to ensure we get the same outcome.
                if (success)
                {
                    Span <byte> digits    = number.Digits;
                    int         numDigits = number.DigitsCount;
                    if (numDigits != 0 && number.Scale == numDigits && digits[numDigits - 1] == '0')
                    {
                        while (numDigits != 0 && digits[numDigits - 1] == '0')
                        {
                            digits[numDigits - 1] = 0;
                            numDigits--;
                        }

                        number.DigitsCount = numDigits;
                        number.CheckConsistency();

                        byte[] buffer2  = new byte[destination.Length];
                        bool   success2 = TryFormatDecimalG(ref number, buffer2, out int bytesWritten2);
                        Debug.Assert(success2);
                        Debug.Assert(bytesWritten2 == bytesWritten);
                        for (int i = 0; i < bytesWritten; i++)
                        {
                            Debug.Assert(destination[i] == buffer2[i]);
                        }
                    }
                }
#endif // DEBUG
                return(success);
            }

            case 'f':
            case 'F':
            {
                byte *pDigits = stackalloc byte[Number.DecimalNumberBufferLength];
                Number.NumberBuffer number = new Number.NumberBuffer(Number.NumberBufferKind.Decimal, pDigits, Number.DecimalNumberBufferLength);

                Number.DecimalToNumber(ref value, ref number);
                byte precision = (format.Precision == StandardFormat.NoPrecision) ? (byte)2 : format.Precision;
                Number.RoundNumber(ref number, number.Scale + precision, isCorrectlyRounded: false);
                Debug.Assert((number.Digits[0] != 0) || !number.IsNegative);           // For Decimals, -0 must print as normal 0. As it happens, Number.RoundNumber already ensures this invariant.
                return(TryFormatDecimalF(ref number, destination, out bytesWritten, precision));
            }

            case 'e':
            case 'E':
            {
                byte *pDigits = stackalloc byte[Number.DecimalNumberBufferLength];
                Number.NumberBuffer number = new Number.NumberBuffer(Number.NumberBufferKind.Decimal, pDigits, Number.DecimalNumberBufferLength);

                Number.DecimalToNumber(ref value, ref number);
                byte precision = (format.Precision == StandardFormat.NoPrecision) ? (byte)6 : format.Precision;
                Number.RoundNumber(ref number, precision + 1, isCorrectlyRounded: false);
                Debug.Assert((number.Digits[0] != 0) || !number.IsNegative);           // For Decimals, -0 must print as normal 0. As it happens, Number.RoundNumber already ensures this invariant.
                return(TryFormatDecimalE(ref number, destination, out bytesWritten, precision, exponentSymbol: (byte)format.Symbol));
            }

            default:
                return(FormattingHelpers.TryFormatThrowFormatException(out bytesWritten));
            }
        }