internal 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 (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 = value._bits.Length; int cuMax; try { cuMax = checked (cuSrc * 10 / 9 + 2); } catch (OverflowException e) { throw new FormatException(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++) { Debug.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.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.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.Format_TooLarge, e); } char[] rgch = new char[rgchBufSize]; int ichDst = cchMax; for (int iuDst = 0; iuDst < cuDst - 1; iuDst++) { uint uDig = rguDst[iuDst]; Debug.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 (!decimalFmt) { // sign = true for negative and false for 0 and positive values bool sign = (value._sign < 0); // The cut-off point to switch (G)eneral from (F)ixed-point to (E)xponential form int precision = 29; int scale = cchMax - ichDst; return(FormatProvider.FormatBigInteger(precision, scale, sign, format, info, rgch, ichDst)); } // 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)); }