2 // System.NumberFormatter.cs
5 // Kazuki Oikawa (kazuki@panicode.com)
8 using System.Collections;
9 using System.Globalization;
16 static char[] digitLowerTable = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
17 static char[] digitUpperTable = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
19 #region NumberToString
20 public static string NumberToString (string format, sbyte value, NumberFormatInfo nfi)
25 ParseBasicFormat (format, out specifier, out precision, out custom);
26 if (!custom && (specifier == 'x' || specifier == 'X'))
27 return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 1, precision, specifier == 'X');
28 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
30 public static string NumberToString (string format, byte value, NumberFormatInfo nfi)
35 ParseBasicFormat (format, out specifier, out precision, out custom);
36 if (!custom && (specifier == 'x' || specifier == 'X'))
37 return FormatHexadecimal (value, true, 1, precision, specifier == 'X');
38 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
40 public static string NumberToString (string format, ushort value, NumberFormatInfo nfi)
45 ParseBasicFormat (format, out specifier, out precision, out custom);
46 if (!custom && (specifier == 'x' || specifier == 'X'))
47 return FormatHexadecimal (value, true, 2, precision, specifier == 'X');
48 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
50 public static string NumberToString (string format, short value, NumberFormatInfo nfi)
55 ParseBasicFormat (format, out specifier, out precision, out custom);
56 if (!custom && (specifier == 'x' || specifier == 'X'))
57 return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 2, precision, specifier == 'X');
58 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
60 public static string NumberToString (string format, uint value, NumberFormatInfo nfi)
65 ParseBasicFormat (format, out specifier, out precision, out custom);
66 if (!custom && (specifier == 'x' || specifier == 'X'))
67 return FormatHexadecimal (value, true, 4, precision, specifier == 'X');
68 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
70 public static string NumberToString (string format, int value, NumberFormatInfo nfi)
75 ParseBasicFormat (format, out specifier, out precision, out custom);
76 if (!custom && (specifier == 'x' || specifier == 'X'))
77 return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-(long)value, value >= 0, 4, precision, specifier == 'X');
78 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
80 public static string NumberToString (string format, ulong value, NumberFormatInfo nfi)
85 ParseBasicFormat (format, out specifier, out precision, out custom);
86 if (!custom && (specifier == 'x' || specifier == 'X'))
87 return FormatHexadecimal (value, true, 8, precision, specifier == 'X');
88 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
90 public static string NumberToString (string format, long value, NumberFormatInfo nfi)
95 ParseBasicFormat (format, out specifier, out precision, out custom);
96 if (!custom && (specifier == 'x' || specifier == 'X'))
97 return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 8, precision, specifier == 'X');
98 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
100 public static string NumberToString (string format, float value, NumberFormatInfo nfi)
105 ParseBasicFormat (format, out specifier, out precision, out custom);
106 if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
107 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
109 public static string NumberToString (string format, double value, NumberFormatInfo nfi)
114 ParseBasicFormat (format, out specifier, out precision, out custom);
115 if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
116 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
118 public static string NumberToString (string format, decimal value, NumberFormatInfo nfi)
123 ParseBasicFormat (format, out specifier, out precision, out custom);
124 if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
125 return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
127 public static string NumberToString (string format, NumberStore ns, NumberFormatInfo nfi, char specifier, int precision, bool custom)
130 return nfi.NaNSymbol;
134 return nfi.PositiveInfinitySymbol;
136 return nfi.NegativeInfinitySymbol;
140 nfi = NumberFormatInfo.GetInstance (null);
143 if (ns.IsFloatingSource)
144 ns.RoundEffectiveDigits (ns.DefaultPrecision);
145 return FormatCustom (format, ns, nfi);
148 if (ns.IsFloatingSource) {
158 ns.RoundEffectiveDigits (ns.DefaultPrecision);
163 ns.RoundEffectiveDigits (ns.DefaultPrecision, ns.IsBankerApplicable, true);
165 ns.RoundEffectiveDigits (precision);
169 ns.RoundEffectiveDigits (ns.DefaultMaxPrecision);
172 if (precision > ns.DefaultPrecision)
173 ns.RoundEffectiveDigits (precision + 1);
175 ns.RoundEffectiveDigits (ns.DefaultPrecision + 1);
183 return FormatCurrency (ns, precision, nfi);
186 return FormatDecimal (ns, precision, nfi);
189 return FormatExponential (ns, precision, nfi, specifier == 'E');
192 return FormatFixedPoint (ns, precision, nfi);
195 if (ns.IsFloatingSource || ns.IsDecimalSource || precision != -1)
196 return FormatGeneral (ns, precision, nfi, specifier == 'G', false);
197 return FormatDecimal (ns, precision, nfi);
200 return FormatNumber (ns, precision, nfi);
203 return FormatPercent (ns, precision, nfi);
206 if (ns.IsFloatingSource) {
207 return FormatGeneral (ns, ns.DefaultPrecision, nfi, true, true);
209 throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
212 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
218 private static void ParseBasicFormat (string format, out char specifier, out int precision, out bool custom)
220 if (format == null || format.Length == 0) {
228 specifier = format[0];
231 if (Char.IsLetter (specifier)) {
232 if (format.Length == 1)
237 for (int i = 1; i < format.Length; i++) {
239 if (char.IsDigit (c)) {
240 precision = precision * 10 + (c - '0');
241 if (precision > 99) {
262 private static void ZeroTrimEnd (StringBuilder sb)
264 ZeroTrimEnd (sb, false);
266 private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
269 for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i --) {
276 sb.Remove (sb.Length - len, len);
281 internal static string FormatCurrency (NumberStore ns, int precision, NumberFormatInfo nfi)
283 precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
284 ns.RoundDecimal (precision);
285 StringBuilder sb = new StringBuilder (ns.IntegerDigits * 2 + precision * 2 + 16);
286 bool needNegativeSign = !ns.Positive && !ns.ZeroOnly;
288 if (!needNegativeSign) {
289 switch (nfi.CurrencyPositivePattern) {
291 sb.Append (nfi.CurrencySymbol);
294 sb.Append (nfi.CurrencySymbol);
299 switch (nfi.CurrencyNegativePattern) {
302 sb.Append (nfi.CurrencySymbol);
305 sb.Append (nfi.NegativeSign);
306 sb.Append (nfi.CurrencySymbol);
309 sb.Append (nfi.CurrencySymbol);
310 sb.Append (nfi.NegativeSign);
313 sb.Append (nfi.CurrencySymbol);
319 sb.Append (nfi.NegativeSign);
322 sb.Append (nfi.NegativeSign);
325 sb.Append (nfi.NegativeSign);
326 sb.Append (nfi.CurrencySymbol);
330 sb.Append (nfi.CurrencySymbol);
334 sb.Append (nfi.CurrencySymbol);
336 sb.Append (nfi.NegativeSign);
340 sb.Append (nfi.CurrencySymbol);
349 ns.AppendIntegerStringWithGroupSeparator (sb, nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);
353 sb.Append (nfi.CurrencyDecimalSeparator);
354 ns.AppendDecimalString (precision, sb);
357 if (!needNegativeSign) {
358 switch (nfi.CurrencyPositivePattern) {
360 sb.Append (nfi.CurrencySymbol);
364 sb.Append (nfi.CurrencySymbol);
368 switch (nfi.CurrencyNegativePattern) {
373 sb.Append (nfi.NegativeSign);
376 sb.Append (nfi.CurrencySymbol);
380 sb.Append (nfi.CurrencySymbol);
383 sb.Append (nfi.NegativeSign);
384 sb.Append (nfi.CurrencySymbol);
387 sb.Append (nfi.CurrencySymbol);
388 sb.Append (nfi.NegativeSign);
392 sb.Append (nfi.CurrencySymbol);
396 sb.Append (nfi.CurrencySymbol);
397 sb.Append (nfi.NegativeSign);
400 sb.Append (nfi.NegativeSign);
403 sb.Append (nfi.NegativeSign);
405 sb.Append (nfi.CurrencySymbol);
412 sb.Append (nfi.CurrencySymbol);
418 return sb.ToString ();
420 internal static string FormatDecimal (NumberStore ns, int precision, NumberFormatInfo nfi)
422 if (ns.IsFloatingSource || ns.IsDecimalSource)
423 throw new FormatException ();
425 precision = precision > 0 ? precision : 1;
426 precision = ns.IntegerDigits > precision ? ns.IntegerDigits : precision;
428 StringBuilder sb = new StringBuilder (precision + nfi.NegativeSign.Length);
430 if (!ns.Positive && !ns.CheckZeroOnlyInteger ()) {
431 sb.Append (nfi.NegativeSign);
434 ns.AppendIntegerString (precision, sb);
436 return sb.ToString ();
438 internal static string FormatFixedPoint (NumberStore ns, int precision, NumberFormatInfo nfi)
440 precision = precision >= 0 ? precision : nfi.NumberDecimalDigits;
441 ns.RoundDecimal (precision);
443 StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + nfi.NumberDecimalSeparator.Length);
445 if (!ns.Positive && !ns.ZeroOnly)
446 cb.Append (nfi.NegativeSign);
448 ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
451 cb.Append (nfi.NumberDecimalSeparator);
452 ns.AppendDecimalString (precision, cb);
455 return cb.ToString ();
458 internal static string FormatGeneral (NumberStore ns)
460 return FormatGeneral (ns, -1, NumberFormatInfo.CurrentInfo, true, false);
462 internal static string FormatGeneral (NumberStore ns, IFormatProvider provider)
464 return FormatGeneral (ns, -1, NumberFormatInfo.GetInstance (provider), true, false);
466 private static string FormatGeneral (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper, bool roundtrip)
471 precision = precision > 0 ? precision : ns.DefaultPrecision;
474 bool expMode = (ns.IsDecimalSource && precision == ns.DefaultPrecision ? false : (ns.IntegerDigits > precision || ns.DecimalPointPosition <= -4));
476 while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
477 if (ns.DecimalPointPosition > 1) {
487 precision = precision < ns.DefaultPrecision + 2 ? (precision < ns.DefaultMaxPrecision ? precision : ns.DefaultMaxPrecision) : ns.DefaultPrecision + 2;
488 StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + 16);
490 if (ns.RoundDecimal (precision - 1)) {
494 } else if (!roundtrip) {
495 if (ns.IsDecimalSource)
496 ns.RoundPos (precision);
498 ns.RoundDecimal (precision, true, false);
502 cb.Append (nfi.NegativeSign);
505 ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
507 if (ns.DecimalDigits > 0) {
508 cb.Append (nfi.NumberDecimalSeparator);
509 ns.AppendDecimalString (ns.DecimalDigits, cb);
519 cb.Append (nfi.PositiveSign);
521 cb.Append (nfi.NegativeSign);
522 exponent = -exponent;
527 } else if (exponent < 10) {
529 cb.Append (digitLowerTable [exponent]);
530 } else if (exponent < 100) {
531 cb.Append (digitLowerTable [exponent / 10 % 10]);
532 cb.Append (digitLowerTable [exponent % 10]);
533 } else if (exponent < 1000) {
534 cb.Append (digitLowerTable [exponent / 100 % 10]);
535 cb.Append (digitLowerTable [exponent / 10 % 10]);
536 cb.Append (digitLowerTable [exponent % 10]);
540 return cb.ToString ();
542 internal static string FormatNumber (NumberStore ns, int precision, NumberFormatInfo nfi)
544 precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
545 StringBuilder sb = new StringBuilder(ns.IntegerDigits * 3 + precision);
547 ns.RoundDecimal (precision);
548 bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
550 if (needNegativeSign) {
551 switch (nfi.NumberNegativePattern) {
556 sb.Append (nfi.NegativeSign);
559 sb.Append (nfi.NegativeSign);
565 ns.AppendIntegerStringWithGroupSeparator (sb, nfi.NumberGroupSizes, nfi.NumberGroupSeparator);
568 sb.Append (nfi.NumberDecimalSeparator);
569 ns.AppendDecimalString (precision, sb);
572 if (needNegativeSign) {
573 switch (nfi.NumberNegativePattern) {
578 sb.Append (nfi.NegativeSign);
582 sb.Append (nfi.NegativeSign);
587 return sb.ToString ();
589 internal static string FormatPercent (NumberStore ns, int precision, NumberFormatInfo nfi)
591 precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
593 ns.RoundDecimal (precision);
594 bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
596 StringBuilder sb = new StringBuilder(ns.IntegerDigits * 2 + precision + 16);
598 if (!needNegativeSign) {
599 if (nfi.PercentPositivePattern == 2) {
600 sb.Append (nfi.PercentSymbol);
603 switch (nfi.PercentNegativePattern) {
605 sb.Append (nfi.NegativeSign);
608 sb.Append (nfi.NegativeSign);
611 sb.Append (nfi.NegativeSign);
612 sb.Append (nfi.PercentSymbol);
617 ns.AppendIntegerStringWithGroupSeparator (sb, nfi.PercentGroupSizes, nfi.PercentGroupSeparator);
620 sb.Append (nfi.PercentDecimalSeparator);
621 ns.AppendDecimalString (precision, sb);
624 if (!needNegativeSign) {
625 switch (nfi.PercentPositivePattern) {
628 sb.Append (nfi.PercentSymbol);
631 sb.Append (nfi.PercentSymbol);
635 switch (nfi.PercentNegativePattern) {
638 sb.Append (nfi.PercentSymbol);
641 sb.Append (nfi.PercentSymbol);
646 return sb.ToString ();
648 unsafe static string FormatHexadecimal (ulong value, bool positive, int byteSize, int precision, bool upper)
651 /* for large values the cast to ulong is going to return 0 anyway (at least on x86, possibly a MS/Mono runtime bug) */
654 value = (ulong)(Math.Pow (2, byteSize * 8)) - value;
661 value = (ulong)(256UL - value);
664 value = (ulong)(65536UL - value);
667 value = (ulong)(4294967296UL - value);
676 char[] digits = (upper ? digitUpperTable : digitLowerTable);
677 int size = precision > 16 ? precision : 16;
678 char* buffer = stackalloc char [size];
679 char* last = buffer + size;
683 *--ptr = digits[value & 0xF];
687 while (ptr == last || last - ptr < precision)
690 return new string (ptr, 0, (int)(last - ptr));
692 internal static string FormatExponential (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
698 StringBuilder sb = new StringBuilder (precision + nfi.PositiveSign.Length + 6);
702 sb.Append ('0', precision);
710 sb.Append (nfi.PositiveSign);
713 return sb.ToString ();
717 while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
718 if (ns.DecimalPointPosition > 1) {
727 if (ns.RoundDecimal (precision)) {
732 StringBuilder cb = new StringBuilder (ns.DecimalDigits + 1 + 8);
735 cb.Append (nfi.NegativeSign);
738 ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
741 cb.Append (nfi.NumberDecimalSeparator);
742 ns.AppendDecimalString (precision, cb);
751 cb.Append (nfi.PositiveSign);
753 cb.Append (nfi.NegativeSign);
754 exponent = -exponent;
759 } else if (exponent < 10) {
761 cb.Append (digitLowerTable [exponent]);
762 } else if (exponent < 100) {
764 cb.Append (digitLowerTable [exponent / 10 % 10]);
765 cb.Append (digitLowerTable [exponent % 10]);
766 } else if (exponent < 1000) {
767 cb.Append (digitLowerTable [exponent / 100 % 10]);
768 cb.Append (digitLowerTable [exponent / 10 % 10]);
769 cb.Append (digitLowerTable [exponent % 10]);
770 /*} else { // exponent range is 0...+-324
773 while (exponent > 0 || --count > 0) {
774 cb.Insert (pos, digitLowerTable [exponent % 10]);
779 return cb.ToString ();
784 internal static string FormatCustom (string format, NumberStore ns, NumberFormatInfo nfi)
786 bool p = ns.Positive;
789 CustomInfo.GetActiveSection (format,ref p, ns.ZeroOnly, ref offset, ref length);
791 return ns.Positive ? String.Empty : nfi.NegativeSign;
795 CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
797 Console.WriteLine("Format : {0}",format);
798 Console.WriteLine("DecimalDigits : {0}",info.DecimalDigits);
799 Console.WriteLine("DecimalPointPos : {0}",info.DecimalPointPos);
800 Console.WriteLine("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
801 Console.WriteLine("IntegerDigits : {0}",info.IntegerDigits);
802 Console.WriteLine("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
803 Console.WriteLine("IntegerHeadPos : {0}",info.IntegerHeadPos);
804 Console.WriteLine("UseExponent : {0}",info.UseExponent);
805 Console.WriteLine("ExponentDigits : {0}",info.ExponentDigits);
806 Console.WriteLine("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
807 Console.WriteLine("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
808 Console.WriteLine("DividePlaces : {0}",info.DividePlaces);
809 Console.WriteLine("Percents : {0}",info.Percents);
810 Console.WriteLine("Permilles : {0}",info.Permilles);
812 StringBuilder sb_int = new StringBuilder(info.IntegerDigits * 2);
813 StringBuilder sb_dec = new StringBuilder(info.DecimalDigits * 2);
814 StringBuilder sb_exp = (info.UseExponent ? new StringBuilder(info.ExponentDigits * 2) : null);
817 if (info.Percents > 0) {
818 ns.Multiply10 (2 * info.Percents);
820 if (info.Permilles > 0) {
821 ns.Multiply10 (3 * info.Permilles);
823 if (info.DividePlaces > 0) {
824 ns.Divide10 (info.DividePlaces);
827 bool expPositive = true;
828 if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
831 while (ns.IntegerDigits > info.IntegerDigits) {
834 if (ns.IntegerDigits == 1 && ns.GetChar (0) == '0')
837 while (ns.IntegerDigits < info.IntegerDigits || (ns.IntegerDigits == info.IntegerDigits && ns.GetChar (0) == '0')) {
842 if (!ns.RoundDecimal (info.DecimalDigits))
847 expPositive = diff <= 0;
848 NumberStore.AppendIntegerStringFromUInt32 (sb_exp, (uint)(diff >= 0 ? diff : -diff));
850 ns.RoundDecimal (info.DecimalDigits);
855 if (info.IntegerDigits != 0 || !ns.CheckZeroOnlyInteger ()) {
856 ns.AppendIntegerString (ns.IntegerDigits, sb_int);
858 /* if (sb_int.Length > info.IntegerDigits) {
860 while (sb_int.Length > info.IntegerDigits && len < sb_int.Length) {
861 if (sb_int [len] == '0')
866 sb_int.Remove (0, len);
869 ns.AppendDecimalString (ns.DecimalDigits, sb_dec);
871 if (info.UseExponent) {
872 if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
875 if (sb_int.Length < info.IntegerDigits)
876 sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
878 while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
879 sb_exp.Insert (0, '0');
881 if (expPositive && !info.ExponentNegativeSignOnly)
882 sb_exp.Insert (0, nfi.PositiveSign);
883 else if(!expPositive)
884 sb_exp.Insert (0, nfi.NegativeSign);
886 if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
887 sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
888 if (info.IntegerDigits == info.IntegerHeadSharpDigits && NumberStore.IsZeroOnly (sb_int))
889 sb_int.Remove (0, sb_int.Length);
892 ZeroTrimEnd (sb_dec, true);
893 while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
895 if (sb_dec.Length > info.DecimalDigits)
896 sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
898 return info.Format (format, offset, length, nfi, ns.Positive, sb_int, sb_dec, sb_exp);
901 private class CustomInfo
903 public bool UseGroup = false;
904 public int DecimalDigits = 0;
905 public int DecimalPointPos = -1;
906 public int DecimalTailSharpDigits = 0;
907 public int IntegerDigits = 0;
908 public int IntegerHeadSharpDigits = 0;
909 public int IntegerHeadPos = 0;
910 public bool UseExponent = false;
911 public int ExponentDigits = 0;
912 public int ExponentTailSharpDigits = 0;
913 public bool ExponentNegativeSignOnly = true;
914 public int DividePlaces = 0;
915 public int Percents = 0;
916 public int Permilles = 0;
918 public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
920 int[] lens = new int [3];
924 for (int i = 0; i < format.Length; i++) {
927 if (c == literal || (literal == '\0' && (c == '\"' || c == '\''))) {
935 if (literal == '\0' && format [i] == ';' && (i == 0 || format [i - 1] != '\\')) {
936 lens [index ++] = i - lastPos;
945 length = format.Length;
949 if (positive || zero) {
954 if (lens [0] + 1 < format.Length) {
956 offset = lens [0] + 1;
957 length = format.Length - offset;
967 offset = lens [0] + lens [1] + 2;
968 length = format.Length - offset;
978 offset = lens [0] + 1;
989 offset = lens [0] + lens [1] + 2;
1000 offset = lens [0] + 1;
1010 throw new ArgumentException ();
1013 public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
1015 char literal = '\0';
1016 bool integerArea = true;
1017 bool decimalArea = false;
1018 bool exponentArea = false;
1019 bool sharpContinues = true;
1021 CustomInfo info = new CustomInfo ();
1022 int groupSeparatorCounter = 0;
1024 for (int i = offset; i - offset < length; i++) {
1025 char c = format [i];
1027 if (c == literal && c != '\0') {
1031 if (literal != '\0')
1034 if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
1035 exponentArea = false;
1036 integerArea = (info.DecimalPointPos < 0);
1037 decimalArea = !integerArea;
1048 if (c == '\"' || c == '\'') {
1053 if (sharpContinues && integerArea)
1054 info.IntegerHeadSharpDigits ++;
1055 else if (decimalArea)
1056 info.DecimalTailSharpDigits ++;
1057 else if (exponentArea)
1058 info.ExponentTailSharpDigits ++;
1063 sharpContinues = false;
1065 info.DecimalTailSharpDigits = 0;
1066 else if (exponentArea)
1067 info.ExponentTailSharpDigits = 0;
1069 if (info.IntegerHeadPos == -1)
1070 info.IntegerHeadPos = i;
1073 info.IntegerDigits ++;
1074 if (groupSeparatorCounter > 0)
1075 info.UseGroup = true;
1076 groupSeparatorCounter = 0;
1077 } else if (decimalArea) {
1078 info.DecimalDigits ++;
1079 } else if (exponentArea) {
1080 info.ExponentDigits ++;
1085 if (info.UseExponent)
1088 info.UseExponent = true;
1089 integerArea = false;
1090 decimalArea = false;
1091 exponentArea = true;
1092 if (i + 1 - offset < length) {
1093 char nc = format [i + 1];
1095 info.ExponentNegativeSignOnly = false;
1096 if (nc == '+' || nc == '-') {
1098 } else if (nc != '0' && nc != '#') {
1099 info.UseExponent = false;
1100 if (info.DecimalPointPos < 0)
1108 integerArea = false;
1110 exponentArea = false;
1111 if (info.DecimalPointPos == -1)
1112 info.DecimalPointPos = i;
1121 if (integerArea && info.IntegerDigits > 0)
1122 groupSeparatorCounter ++;
1129 if (info.ExponentDigits == 0)
1130 info.UseExponent = false;
1132 info.IntegerHeadSharpDigits = 0;
1134 if (info.DecimalDigits == 0)
1135 info.DecimalPointPos = -1;
1137 info.DividePlaces += groupSeparatorCounter * 3;
1142 public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
1144 StringBuilder sb = new StringBuilder ();
1145 char literal = '\0';
1146 bool integerArea = true;
1147 bool decimalArea = false;
1148 int intSharpCounter = 0;
1149 int sb_int_index = 0;
1150 int sb_dec_index = 0;
1152 int[] groups = nfi.NumberGroupSizes;
1153 string groupSeparator = nfi.NumberGroupSeparator;
1154 int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0, fraction = 0;
1155 if (UseGroup && groups.Length > 0) {
1156 intLen = sb_int.Length;
1157 for (int i = 0; i < groups.Length; i++) {
1158 total += groups [i];
1159 if (total <= intLen)
1162 groupSize = groups [groupIndex];
1163 fraction = intLen > total ? intLen - total : 0;
1164 if (groupSize == 0) {
1165 while (groupIndex >= 0 && groups [groupIndex] == 0)
1168 groupSize = fraction > 0 ? fraction : groups [groupIndex];
1170 if (fraction == 0) {
1171 counter = groupSize;
1173 groupIndex += fraction / groupSize;
1174 counter = fraction % groupSize;
1176 counter = groupSize;
1184 for (int i = offset; i - offset < length; i++) {
1185 char c = format [i];
1187 if (c == literal && c != '\0') {
1191 if (literal != '\0') {
1199 if (i - offset < length)
1200 sb.Append (format [i]);
1204 if (c == '\"' || c == '\'') {
1213 if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
1214 while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
1215 sb.Append (sb_int[ sb_int_index++]);
1216 if (UseGroup && --intLen > 0 && --counter == 0) {
1217 sb.Append (groupSeparator);
1218 if (--groupIndex < groups.Length && groupIndex >= 0)
1219 groupSize = groups [groupIndex];
1220 counter = groupSize;
1224 } else if (decimalArea) {
1225 if (sb_dec_index < sb_dec.Length)
1226 sb.Append (sb_dec [sb_dec_index++]);
1234 if (sb_exp == null || !UseExponent) {
1243 for (q = i + 1; q - offset < length; q++) {
1244 if (format [q] == '0') {
1248 if (q == i + 1 && (format [q] == '+' || format [q] == '-')) {
1258 integerArea = (DecimalPointPos < 0);
1259 decimalArea = !integerArea;
1269 if (DecimalPointPos == i) {
1270 if (DecimalDigits > 0) {
1271 while (sb_int_index < sb_int.Length)
1272 sb.Append (sb_int [sb_int_index++]);
1274 if (sb_dec.Length > 0)
1275 sb.Append (nfi.NumberDecimalSeparator);
1277 integerArea = false;
1283 sb.Append (nfi.PercentSymbol);
1286 sb.Append (nfi.PerMilleSymbol);
1295 sb.Insert (0, nfi.NegativeSign);
1297 return sb.ToString ();
1303 #region Internal structures
1304 internal struct NumberStore
1311 int _defMaxPrecision;
1316 static uint [] IntList = new uint [] {
1329 static ulong [] ULongList = new ulong [] {
1348 1000000000000000000,
1349 10000000000000000000,
1352 #region Constructors
1353 public NumberStore (long value)
1355 _infinity = _NaN = false;
1357 _defMaxPrecision = _defPrecision = 19;
1358 _positive = value >= 0;
1361 _digits = new byte []{0};
1366 ulong v = (ulong)(_positive ? value : -value);
1378 else if (v < 100000)
1380 else if (v < 1000000)
1382 else if (v < 10000000)
1384 else if (v < 100000000)
1386 else if (v < 1000000000)
1388 else if (v < 10000000000)
1390 else if (v < 100000000000)
1392 else if (v < 1000000000000)
1394 else if (v < 10000000000000)
1396 else if (v < 100000000000000)
1398 else if (v < 1000000000000000)
1400 else if (v < 10000000000000000)
1402 else if (v < 100000000000000000)
1404 else if (v < 1000000000000000000)
1409 _digits = new byte [i + 1];
1411 ulong n = v / ULongList [i];
1412 _digits [j++] = (byte)n;
1413 v -= ULongList [i--] * n;
1416 _decPointPos = _digits.Length;
1418 public NumberStore (int value)
1420 _infinity = _NaN = false;
1422 _defMaxPrecision = _defPrecision = 10;
1423 _positive = value >= 0;
1426 _digits = new byte []{0};
1431 uint v = (uint)(_positive ? value : -value);
1443 else if (v < 100000)
1445 else if (v < 1000000)
1447 else if (v < 10000000)
1449 else if (v < 100000000)
1451 else if (v < 1000000000)
1456 _digits = new byte [i + 1];
1458 uint n = v / IntList [i];
1459 _digits [j++] = (byte)n;
1460 v -= IntList [i--] * n;
1463 _decPointPos = _digits.Length;
1465 public NumberStore (short value) : this ((int)value)
1468 _defMaxPrecision = _defPrecision = 5;
1470 public NumberStore (sbyte value) : this ((int)value)
1473 _defMaxPrecision = _defPrecision = 3;
1476 public NumberStore (ulong value)
1478 _infinity = _NaN = false;
1480 _defMaxPrecision = _defPrecision = 20;
1484 _digits = new byte []{0};
1493 else if (value < 100)
1495 else if (value < 1000)
1497 else if (value < 10000)
1499 else if (value < 100000)
1501 else if (value < 1000000)
1503 else if (value < 10000000)
1505 else if (value < 100000000)
1507 else if (value < 1000000000)
1509 else if (value < 10000000000)
1511 else if (value < 100000000000)
1513 else if (value < 1000000000000)
1515 else if (value < 10000000000000)
1517 else if (value < 100000000000000)
1519 else if (value < 1000000000000000)
1521 else if (value < 10000000000000000)
1523 else if (value < 100000000000000000)
1525 else if (value < 1000000000000000000)
1527 else if (value < 10000000000000000000)
1532 _digits = new byte [i + 1];
1534 ulong n = value / ULongList [i];
1535 _digits [j++] = (byte)n;
1536 value -= ULongList [i--] * n;
1539 _decPointPos = _digits.Length;
1541 public NumberStore (uint value)
1543 _infinity = _NaN = false;
1546 _defMaxPrecision = _defPrecision = 10;
1549 _digits = new byte []{0};
1558 else if (value < 100)
1560 else if (value < 1000)
1562 else if (value < 10000)
1564 else if (value < 100000)
1566 else if (value < 1000000)
1568 else if (value < 10000000)
1570 else if (value < 100000000)
1572 else if (value < 1000000000)
1577 _digits = new byte [i + 1];
1579 uint n = value / IntList [i];
1580 _digits [j++] = (byte)n;
1581 value -= IntList [i--] * n;
1584 _decPointPos = _digits.Length;
1586 public NumberStore (ushort value) : this ((uint)value)
1589 _defMaxPrecision = _defPrecision = 5;
1591 public NumberStore (byte value) : this ((uint)value)
1594 _defMaxPrecision = _defPrecision = 3;
1597 public NumberStore(double value)
1602 _defMaxPrecision = _defPrecision + 2;
1604 if (double.IsNaN (value) || double.IsInfinity (value)) {
1605 _NaN = double.IsNaN (value);
1606 _infinity = double.IsInfinity (value);
1607 _positive = value > 0;
1611 _NaN = _infinity = false;
1614 long bits = BitConverter.DoubleToInt64Bits (value);
1615 _positive = (bits >= 0);
1616 int e = (int) ((bits >> 52) & 0x7ffL);
1617 long m = bits & 0xfffffffffffffL;
1619 if (e == 0 && m == 0) {
1621 _digits = new byte []{0};
1628 } else if (e != 0) {
1635 while ((m & 1) == 0) {
1643 byte[] temp = new byte [56];
1644 for (int i = temp.Length - 1; i >= 0; i--, length++) {
1645 temp [i] = (byte)(mt % 10);
1651 _decPointPos = temp.Length - 1;
1654 for (int i = 0; i < e; i++) {
1655 if (MultiplyBy (ref temp, ref length, 2)) {
1660 for (int i = 0; i < -e; i++) {
1661 if (MultiplyBy (ref temp, ref length, 5)) {
1670 for (int i = 0; i < temp.Length; i++)
1671 if (temp [i] != 0) {
1672 _decPointPos -= i - 1;
1673 _digits = new byte [temp.Length - i];
1674 for (int q = i; q < temp.Length; q++) {
1675 _digits [q - i] = temp [q];
1677 ulv = ulv * 10 + temp [q];
1684 RoundEffectiveDigits (17, true, true);
1686 public NumberStore(float value)
1691 _defMaxPrecision = _defPrecision + 2;
1693 if (float.IsNaN (value) || float.IsInfinity (value)) {
1694 _NaN = float.IsNaN (value);
1695 _infinity = float.IsInfinity (value);
1696 _positive = value > 0;
1700 _infinity = _NaN = false;
1702 long bits = BitConverter.DoubleToInt64Bits (value);
1703 _positive = (bits >= 0);
1704 int e = (int) ((bits >> 52) & 0x7ffL);
1705 long m = bits & 0xfffffffffffffL;
1707 if (e == 0 && m == 0) {
1709 _digits = new byte []{0};
1716 } else if (e != 0) {
1723 while ((m & 1) == 0) {
1731 byte[] temp = new byte [26];
1732 for (int i = temp.Length - 1; i >= 0; i--, length++) {
1733 temp [i] = (byte)(mt % 10);
1739 _decPointPos = temp.Length - 1;
1742 for (int i = 0; i < e; i++) {
1743 if (MultiplyBy (ref temp, ref length, 2)) {
1748 for (int i = 0; i < -e; i++) {
1749 if (MultiplyBy (ref temp, ref length, 5)) {
1758 for (int i = 0; i < temp.Length; i++)
1759 if (temp [i] != 0) {
1760 _decPointPos -= i - 1;
1761 _digits = new byte [temp.Length - i];
1762 for (int q = i; q < temp.Length; q++) {
1763 _digits [q - i] = temp [q];
1765 ulv = ulv * 10 + temp [q];
1772 RoundEffectiveDigits (9, true, true);
1775 internal bool MultiplyBy (ref byte[] buffer,ref int length, int amount)
1779 int start = buffer.Length - length - 1;
1780 if (start < 0) start = 0;
1782 for (int i = buffer.Length - 1; i > start; i--) {
1783 ret = buffer [i] * amount + mod;
1785 buffer [i] = (byte)(ret % 10);
1789 length = buffer.Length - start;
1792 buffer [0] = (byte)mod;
1793 Array.Copy (buffer, 0, buffer, 1, buffer.Length - 1);
1798 buffer [start] = (byte)mod;
1806 public NumberStore (decimal value)
1808 int[] bits = decimal.GetBits (value);
1809 _positive = (bits [3] & 0x80000000) == 0;
1810 bits[3] = bits [3] & 0x7FFFFFFF;
1811 int ss = (bits [3] & 0x1F0000) >> 16;
1812 ulong lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
1813 ulong hi = (uint)bits [2];
1817 while (hi > 0 || lo > 0) {
1819 DivideDecimal (ref lo, ref hi, 10, ref rest);
1822 lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
1823 hi = (uint)bits [2];
1825 _digits = new byte [digits];
1827 while (hi > 0 || lo > 0) {
1828 DivideDecimal (ref lo, ref hi, 10, ref rest);
1829 _digits [--i] = (byte)rest;
1832 _infinity = _NaN = false;
1833 _decPointPos = _digits.Length - ss;
1834 _defPrecision = _defMaxPrecision = 100;
1837 static int DivideDecimal (ref ulong lo, ref ulong hi, uint factor, ref uint rest)
1842 a = (uint)(h >> 32);
1850 hi = b << 32 | (uint)c;
1853 a |= (uint)(h >> 32);
1860 lo = b << 32 | (uint)c;
1865 return (a >= factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
1869 #region Public Property
1872 get { return _NaN; }
1874 public bool IsInfinity {
1875 get { return _infinity; }
1877 public int DecimalPointPosition {
1878 get { return _decPointPos; }
1880 public bool Positive {
1881 get { return _positive; }
1882 set { _positive = value;}
1884 public int DefaultPrecision {
1885 get { return _defPrecision; }
1887 public int DefaultMaxPrecision {
1888 get { return _defMaxPrecision; }
1890 public int DefaultByteSize {
1891 get { return _defByteSize; }
1893 public bool HasDecimal {
1894 get { return _digits.Length > _decPointPos; }
1896 public int IntegerDigits {
1897 get { return _decPointPos > 0 ? _decPointPos : 1; }
1899 public int DecimalDigits {
1900 get { return HasDecimal ? _digits.Length - _decPointPos : 0; }
1902 public bool IsFloatingSource {
1903 get { return _defPrecision == 15 || _defPrecision == 7; }
1905 public bool IsDecimalSource {
1906 get { return _defPrecision > 30; }
1908 public bool IsBankerApplicable {
1910 if ((_digits == null) || (_digits.Length < 2))
1912 return ((_digits [_digits.Length - 2] & 1) == 1);
1915 public bool ZeroOnly {
1917 for (int i = 0; i < _digits.Length; i++)
1918 if (_digits [i] != 0)
1925 #region Public Method
1928 public bool RoundPos (int pos)
1930 return RoundPos (pos, true);
1932 public bool RoundPos (int pos, bool carryFive)
1936 if (_decPointPos <= 0)
1937 pos = pos - _decPointPos - 1;
1939 if (pos >= _digits.Length)
1943 _digits = new byte [1];
1950 for (int i = pos; i >= 0; i--) {
1951 RoundHelper (i, carryFive, ref carry);
1957 byte[] temp = new byte [_digits.Length + 1];
1958 _digits.CopyTo (temp, 1);
1965 for (int i = pos; i < _digits.Length; i++)
1967 TrimDecimalEndZeros ();
1971 public bool RoundDecimal (int decimals)
1973 return RoundDecimal (decimals, true, true);
1975 public bool RoundDecimal (int decimals, bool carryFive, bool countZero)
1979 if (countZero || (_decPointPos > 0))
1980 decimals += _decPointPos;
1982 if (!HasDecimal || decimals >= _digits.Length)
1986 _digits = new byte [1];
1993 for (int i = decimals; i >= 0; i--) {
1994 RoundHelper (i, carryFive, ref carry);
2000 byte[] temp = new byte [_digits.Length + 1];
2001 _digits.CopyTo (temp, 1);
2008 for (int i = decimals; i < _digits.Length; i++)
2010 TrimDecimalEndZeros ();
2014 void RoundHelper (int index, bool carryFive, ref bool carry)
2017 if (_digits [index] == 9) {
2019 _digits [index] = 0;
2024 } else if (_digits [index] >= (carryFive ? 5 : 6)) {
2028 public bool RoundEffectiveDigits (int digits)
2030 return RoundEffectiveDigits (digits, true, true);
2032 public bool RoundEffectiveDigits (int digits, bool carryFive, bool carryEven)
2036 if (digits >= _digits.Length || digits < 0)
2039 if (digits + 1 < _digits.Length && _digits [digits + 1] == 5 && _digits [digits] % 2 == (carryEven ? 0 : 1))
2042 /// are we cutting from the maximum precision ?
2043 if (_digits.Length == _defMaxPrecision) {
2044 // special case if we *aren't* cutting inside the extra precision (e.g. 16 on 17)
2045 if (digits != _defMaxPrecision - 1) {
2046 // ok, here we look at the *two* extra numbers we're keeping
2047 // (we keep 17 digits while the true precision is 15 digits).
2048 int extra = _digits[_defMaxPrecision - 2] * 10 + _digits[_defMaxPrecision - 1];
2049 carry = (extra >= 50);
2051 _digits[_defMaxPrecision - 2] = 0;
2052 _digits[_defMaxPrecision - 1] = 0;
2053 int d = _digits.Length - 3;
2054 CarryPropagation (ref d, carryFive, ref carry);
2058 CarryPropagation (ref digits, carryFive, ref carry);
2060 for (int i = digits; i < _digits.Length; i++)
2062 TrimDecimalEndZeros ();
2067 private void CarryPropagation (ref int digits, bool carryFive, ref bool carry)
2069 for (int i = digits; i >= 0; i--) {
2070 RoundHelper (i, carryFive, ref carry);
2076 byte[] temp = new byte[_digits.Length + 1];
2077 _digits.CopyTo (temp, 1);
2088 public void TrimDecimalEndZeros ()
2091 for (int i = _digits.Length - 1; i >= 0; i --) {
2092 if (_digits [i] != 0)
2098 byte[] temp = new byte [_digits.Length - len];
2099 Array.Copy (_digits, 0, temp, 0, temp.Length);
2103 public void TrimIntegerStartZeros ()
2105 if (_decPointPos < 0 && _decPointPos >= _digits.Length)
2109 for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
2110 if (_digits [i] != 0)
2115 if (len == _decPointPos)
2118 if (len == _digits.Length) {
2119 _digits = new byte [1];
2123 } else if (len > 0) {
2124 byte[] temp = new byte [_digits.Length - len];
2125 Array.Copy (_digits, len, temp, 0, temp.Length);
2127 _decPointPos -= len;
2134 public void AppendIntegerString (int minLength, StringBuilder cb)
2136 if (IntegerDigits == 0) {
2137 cb.Append ('0', minLength);
2140 if (_decPointPos <= 0) {
2141 cb.Append ('0', minLength);
2145 if (_decPointPos < minLength)
2146 cb.Append ('0', minLength - _decPointPos);
2148 for (int i = 0; i < _decPointPos; i++) {
2149 if (i < _digits.Length)
2150 cb.Append ((char)('0' + _digits [i]));
2155 public void AppendIntegerStringWithGroupSeparator (StringBuilder sb, int[] groups, string groupSeparator)
2157 if (_decPointPos <= 0) {
2162 int intLen = IntegerDigits;
2165 for (int i = 0; i < groups.Length; i++) {
2166 total += groups [i];
2167 if (total <= intLen)
2171 if (groups.Length > 0 && total > 0) {
2173 int groupSize = groups [groupIndex];
2174 int fraction = intLen > total ? intLen - total : 0;
2175 if (groupSize == 0) {
2176 while (groupIndex >= 0 && groups [groupIndex] == 0)
2179 groupSize = fraction > 0 ? fraction : groups [groupIndex];
2181 if (fraction == 0) {
2182 counter = groupSize;
2184 groupIndex += fraction / groupSize;
2185 counter = fraction % groupSize;
2187 counter = groupSize;
2192 for (int i = 0; i < _decPointPos; i++) {
2193 if (i < _digits.Length) {
2194 sb.Append ((char)('0' + _digits [i]));
2199 if (i < intLen - 1 && --counter == 0) {
2200 sb.Append (groupSeparator);
2201 if (--groupIndex < groups.Length && groupIndex >= 0)
2202 groupSize = groups [groupIndex];
2203 counter = groupSize;
2207 for (int i = 0; i < _decPointPos; i++) {
2208 if (i < _digits.Length) {
2209 sb.Append ((char)('0' + _digits [i]));
2219 public string GetDecimalString (int precision)
2222 return new string ('0', precision);
2224 StringBuilder sb = new StringBuilder (precision);
2225 for (int i = _decPointPos; i < _digits.Length && i < precision + _decPointPos; i++) {
2227 sb.Append ((char)('0' + _digits [i]));
2231 if (sb.Length < precision)
2232 sb.Append ('0', precision - sb.Length);
2233 else if (sb.Length > precision)
2234 sb.Remove (0, precision);
2235 return sb.ToString ();
2238 public void AppendDecimalString (int precision, StringBuilder cb)
2241 cb.Append ('0', precision);
2245 int i = _decPointPos;
2246 for (; i < _digits.Length && i < precision + _decPointPos; i++) {
2248 cb.Append ((char)('0' + _digits [i]));
2255 cb.Append ('0', precision - i);
2260 public bool CheckZeroOnlyInteger ()
2262 for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
2263 if (_digits [i] != 0)
2268 public void Multiply10 (int count)
2273 _decPointPos += count;
2275 TrimIntegerStartZeros ();
2277 public void Divide10 (int count)
2282 _decPointPos -= count;
2284 public override string ToString()
2286 StringBuilder sb = new StringBuilder ();
2287 AppendIntegerString (IntegerDigits, sb);
2290 AppendDecimalString (DecimalDigits, sb);
2292 return sb.ToString ();
2294 public char GetChar (int pos)
2296 if (_decPointPos <= 0)
2297 pos += _decPointPos - 1;
2299 if (pos < 0 || pos >= _digits.Length)
2302 return (char)('0' + _digits [pos]);
2304 public byte GetDigitByte (int pos)
2306 if (_decPointPos <= 0)
2307 pos += _decPointPos - 1;
2309 if (pos < 0 || pos >= _digits.Length)
2312 return _digits [pos];
2314 public NumberStore GetClone ()
2316 NumberStore ns = new NumberStore ();
2318 ns._decPointPos = this._decPointPos;
2319 ns._defMaxPrecision = this._defMaxPrecision;
2320 ns._defPrecision = this._defPrecision;
2321 ns._digits = (byte[])this._digits.Clone ();
2322 ns._infinity = this._infinity;
2323 ns._NaN = this._NaN;
2324 ns._positive = this._positive;
2328 public int GetDecimalPointPos ()
2330 return _decPointPos;
2332 public void SetDecimalPointPos (int dp)
2340 #region Public Static Method
2341 public static bool IsZeroOnly (StringBuilder sb)
2343 for (int i = 0; i < sb.Length; i++)
2344 if (char.IsDigit (sb [i]) && sb [i] != '0')
2348 public static void AppendIntegerStringFromUInt32 (StringBuilder sb, uint v)
2351 throw new ArgumentException ();
2355 if (v >= 1000000000)
2357 else if (v >= 100000000)
2359 else if (v >= 10000000)
2361 else if (v >= 1000000)
2363 else if (v >= 100000)
2365 else if (v >= 10000)
2376 uint n = v / IntList [i];
2377 sb.Append (NumberFormatter.digitLowerTable [n]);
2378 v -= IntList [i--] * n;