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)
22 return NumberToString (format, new NumberStore (value), nfi);
24 public static string NumberToString (string format, byte value, NumberFormatInfo nfi)
26 return NumberToString (format, new NumberStore (value), nfi);
28 public static string NumberToString (string format, ushort value, NumberFormatInfo nfi)
30 return NumberToString (format, new NumberStore (value), nfi);
32 public static string NumberToString (string format, short value, NumberFormatInfo nfi)
34 return NumberToString (format, new NumberStore (value), nfi);
36 public static string NumberToString (string format, uint value, NumberFormatInfo nfi)
38 return NumberToString (format, new NumberStore (value), nfi);
40 public static string NumberToString (string format, int value, NumberFormatInfo nfi)
42 return NumberToString (format, new NumberStore (value), nfi);
44 public static string NumberToString (string format, ulong value, NumberFormatInfo nfi)
46 return NumberToString (format, new NumberStore (value), nfi);
48 public static string NumberToString (string format, long value, NumberFormatInfo nfi)
50 return NumberToString (format, new NumberStore (value), nfi);
52 public static string NumberToString (string format, float value, NumberFormatInfo nfi)
54 return NumberToString (format, new NumberStore (value), nfi);
56 public static string NumberToString (string format, double value, NumberFormatInfo nfi)
58 return NumberToString (format, new NumberStore (value), nfi);
60 public static string NumberToString (string format, NumberStore ns, NumberFormatInfo nfi)
67 return nfi.PositiveInfinitySymbol;
69 return nfi.NegativeInfinitySymbol;
76 if (format == null || format.Length == 0)
80 nfi = NumberFormatInfo.GetInstance (null);
82 if (!ParseBasicFormat (format, out specifier, out precision, out custom))
83 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
86 if (ns.IsFloatingSource)
87 ns.RoundEffectiveDigits (ns.DefaultPrecision);
88 return FormatCustom (format, ns, nfi);
91 if (ns.IsFloatingSource) {
101 ns.RoundEffectiveDigits (ns.DefaultPrecision);
106 ns.RoundEffectiveDigits (ns.DefaultPrecision);
108 ns.RoundEffectiveDigits (precision);
112 ns.RoundEffectiveDigits (ns.DefaultMaxPrecision);
115 if (precision > ns.DefaultPrecision)
116 ns.RoundEffectiveDigits (precision + 1);
118 ns.RoundEffectiveDigits (ns.DefaultPrecision + 1);
126 return FormatCurrency (ns, precision, nfi);
129 return FormatDecimal (ns, precision, nfi);
132 return FormatExponential (ns, precision, nfi, specifier == 'E');
135 return FormatFixedPoint (ns, precision, nfi);
138 return FormatGeneral (ns, precision, nfi, specifier == 'G');
141 return FormatNumber (ns, precision, nfi);
144 return FormatPercent (ns, precision, nfi);
147 if (ns.IsFloatingSource) {
148 return FormatGeneral (ns, ns.DefaultMaxPrecision, nfi, true);
150 throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
153 case 'X': return FormatHexadecimal (ns, precision, nfi, specifier == 'X');
155 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
161 private static bool ParseBasicFormat (string format, out char specifier, out int precision, out bool custom)
167 if (format.Length < 1)
170 specifier = format [0];
172 if (Char.IsLetter (specifier)) {
173 if (format.Length == 1)
178 for (int i = 1; i < format.Length; i++) {
180 if (char.IsDigit (c)) {
181 precision = precision * 10 + (c - '0');
182 if (precision > 99) {
203 private static void ZeroTrimEnd (StringBuilder sb)
205 ZeroTrimEnd (sb, false);
207 private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
210 for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i --) {
217 sb.Remove (sb.Length - len, len);
222 internal static string FormatCurrency (NumberStore ns, int precision, NumberFormatInfo nfi)
224 precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
225 ns.RoundDecimal (precision);
226 StringBuilder sb = new StringBuilder (ns.IntegerDigits * 2 + precision * 2 + 16);
227 bool needNegativeSign = !ns.Positive && !ns.ZeroOnly;
229 if (!needNegativeSign) {
230 switch (nfi.CurrencyPositivePattern) {
232 sb.Append (nfi.CurrencySymbol);
235 sb.Append (nfi.CurrencySymbol);
240 switch (nfi.CurrencyNegativePattern) {
243 sb.Append (nfi.CurrencySymbol);
246 sb.Append (nfi.NegativeSign);
247 sb.Append (nfi.CurrencySymbol);
250 sb.Append (nfi.CurrencySymbol);
251 sb.Append (nfi.NegativeSign);
254 sb.Append (nfi.CurrencySymbol);
260 sb.Append (nfi.NegativeSign);
263 sb.Append (nfi.NegativeSign);
266 sb.Append (nfi.NegativeSign);
267 sb.Append (nfi.CurrencySymbol);
271 sb.Append (nfi.CurrencySymbol);
275 sb.Append (nfi.CurrencySymbol);
277 sb.Append (nfi.NegativeSign);
281 sb.Append (nfi.CurrencySymbol);
290 ns.AppendIntegerStringWithGroupSeparator (sb, nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);
294 sb.Append (nfi.CurrencyDecimalSeparator);
295 ns.AppendDecimalString (precision, sb);
298 if (!needNegativeSign) {
299 switch (nfi.CurrencyPositivePattern) {
301 sb.Append (nfi.CurrencySymbol);
305 sb.Append (nfi.CurrencySymbol);
309 switch (nfi.CurrencyNegativePattern) {
314 sb.Append (nfi.NegativeSign);
317 sb.Append (nfi.CurrencySymbol);
321 sb.Append (nfi.CurrencySymbol);
324 sb.Append (nfi.NegativeSign);
325 sb.Append (nfi.CurrencySymbol);
328 sb.Append (nfi.CurrencySymbol);
329 sb.Append (nfi.NegativeSign);
333 sb.Append (nfi.CurrencySymbol);
337 sb.Append (nfi.CurrencySymbol);
338 sb.Append (nfi.NegativeSign);
341 sb.Append (nfi.NegativeSign);
344 sb.Append (nfi.NegativeSign);
346 sb.Append (nfi.CurrencySymbol);
353 sb.Append (nfi.CurrencySymbol);
359 return sb.ToString ();
361 internal static string FormatDecimal (NumberStore ns, int precision, NumberFormatInfo nfi)
363 if (ns.IsFloatingSource)
364 throw new FormatException ();
366 precision = precision > 0 ? precision : 1;
367 precision = ns.IntegerDigits > precision ? ns.IntegerDigits : precision;
369 StringBuilder sb = new StringBuilder (precision + nfi.NegativeSign.Length);
371 if (!ns.Positive && !ns.CheckZeroOnlyInteger ()) {
372 sb.Append (nfi.NegativeSign);
375 ns.AppendIntegerString (precision, sb);
377 return sb.ToString ();
379 internal static string FormatFixedPoint (NumberStore ns, int precision, NumberFormatInfo nfi)
381 precision = precision >= 0 ? precision : nfi.NumberDecimalDigits;
382 ns.RoundDecimal (precision);
384 StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + nfi.NumberDecimalSeparator.Length);
386 if (!ns.Positive && !ns.ZeroOnly)
387 cb.Append (nfi.NegativeSign);
389 ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
392 cb.Append (nfi.NumberDecimalSeparator);
393 ns.AppendDecimalString (precision, cb);
396 return cb.ToString ();
399 internal static string FormatGeneral (NumberStore ns)
401 return FormatGeneral (ns, -1, NumberFormatInfo.CurrentInfo, true);
403 internal static string FormatGeneral (NumberStore ns, IFormatProvider provider)
405 return FormatGeneral (ns, -1, NumberFormatInfo.GetInstance (provider), true);
407 internal static string FormatGeneral (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
412 precision = precision > 0 ? precision : ns.DefaultPrecision;
415 bool expMode = (ns.IntegerDigits > precision || ns.DecimalPointPosition <= -4);
417 while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
418 if (ns.DecimalPointPosition > 1) {
428 precision = precision < ns.DefaultPrecision + 2 ? (precision < 17 ? precision : 17) : ns.DefaultPrecision + 2;
429 StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + 16);
431 if (ns.RoundDecimal (precision - 1)) {
436 ns.RoundDecimal (precision);
440 cb.Append (nfi.NegativeSign);
443 ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
445 if (ns.DecimalDigits > 0) {
446 cb.Append (nfi.NumberDecimalSeparator);
447 ns.AppendDecimalString (ns.DecimalDigits, cb);
457 cb.Append (nfi.PositiveSign);
459 cb.Append (nfi.NegativeSign);
460 exponent = -exponent;
465 } else if (exponent < 10) {
467 cb.Append (digitLowerTable [exponent]);
468 } else if (exponent < 100) {
469 cb.Append (digitLowerTable [exponent / 10 % 10]);
470 cb.Append (digitLowerTable [exponent % 10]);
471 } else if (exponent < 1000) {
472 cb.Append (digitLowerTable [exponent / 100 % 10]);
473 cb.Append (digitLowerTable [exponent / 10 % 10]);
474 cb.Append (digitLowerTable [exponent % 10]);
478 return cb.ToString ();
480 internal static string FormatNumber (NumberStore ns, int precision, NumberFormatInfo nfi)
482 precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
483 StringBuilder sb = new StringBuilder(ns.IntegerDigits * 3 + precision);
485 ns.RoundDecimal (precision);
486 bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
488 if (needNegativeSign) {
489 switch (nfi.NumberNegativePattern) {
494 sb.Append (nfi.NegativeSign);
497 sb.Append (nfi.NegativeSign);
503 ns.AppendIntegerStringWithGroupSeparator (sb, nfi.NumberGroupSizes, nfi.NumberGroupSeparator);
506 sb.Append (nfi.NumberDecimalSeparator);
507 ns.AppendDecimalString (precision, sb);
510 if (needNegativeSign) {
511 switch (nfi.NumberNegativePattern) {
516 sb.Append (nfi.NegativeSign);
520 sb.Append (nfi.NegativeSign);
525 return sb.ToString ();
527 internal static string FormatPercent (NumberStore ns, int precision, NumberFormatInfo nfi)
529 precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
531 ns.RoundDecimal (precision);
532 bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
534 StringBuilder sb = new StringBuilder(ns.IntegerDigits * 2 + precision + 16);
536 if (!needNegativeSign) {
537 if (nfi.PercentPositivePattern == 2) {
538 sb.Append (nfi.PercentSymbol);
541 switch (nfi.PercentNegativePattern) {
543 sb.Append (nfi.NegativeSign);
546 sb.Append (nfi.NegativeSign);
549 sb.Append (nfi.NegativeSign);
550 sb.Append (nfi.PercentSymbol);
555 ns.AppendIntegerStringWithGroupSeparator (sb, nfi.PercentGroupSizes, nfi.PercentGroupSeparator);
558 sb.Append (nfi.PercentDecimalSeparator);
559 ns.AppendDecimalString (precision, sb);
562 if (!needNegativeSign) {
563 switch (nfi.PercentPositivePattern) {
566 sb.Append (nfi.PercentSymbol);
569 sb.Append (nfi.PercentSymbol);
573 switch (nfi.PercentNegativePattern) {
576 sb.Append (nfi.PercentSymbol);
579 sb.Append (nfi.PercentSymbol);
584 return sb.ToString ();
586 internal static string FormatHexadecimal (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
588 if (ns.IsFloatingSource)
589 throw new FormatException ();
591 int intSize = ns.DefaultByteSize;
593 for (int i = 0; i < ns.IntegerDigits; i++) {
595 value += ns.GetDigitByte (i);
599 value = (ulong)(Math.Pow (2, intSize * 8)) - value;
602 char[] digits = (upper ? digitUpperTable : digitLowerTable);
603 CharBuffer sb = new CharBuffer (16 + precision + 1);
606 sb.InsertToFront (digits [value % 16]);
611 sb.InsertToFront ('0');
613 if (sb.Length < precision)
614 sb.InsertToFront ('0', precision - sb.Length);
616 return sb.ToString ();
618 internal static string FormatExponential (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
624 StringBuilder sb = new StringBuilder (precision + nfi.PositiveSign.Length + 6);
628 sb.Append ('0', precision);
636 sb.Append (nfi.PositiveSign);
639 return sb.ToString ();
643 while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
644 if (ns.DecimalPointPosition > 1) {
653 if (ns.RoundDecimal (precision)) {
658 StringBuilder cb = new StringBuilder (ns.DecimalDigits + 1 + 8);
661 cb.Append (nfi.NegativeSign);
664 ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
667 cb.Append (nfi.NumberDecimalSeparator);
668 ns.AppendDecimalString (precision, cb);
677 cb.Append (nfi.PositiveSign);
679 cb.Append (nfi.NegativeSign);
680 exponent = -exponent;
685 } else if (exponent < 10) {
687 cb.Append (digitLowerTable [exponent]);
688 } else if (exponent < 100) {
690 cb.Append (digitLowerTable [exponent / 10 % 10]);
691 cb.Append (digitLowerTable [exponent % 10]);
692 } else if (exponent < 1000) {
693 cb.Append (digitLowerTable [exponent / 100 % 10]);
694 cb.Append (digitLowerTable [exponent / 10 % 10]);
695 cb.Append (digitLowerTable [exponent % 10]);
696 /*} else { // exponent range is 0
\81`
\81}324
699 while (exponent > 0 || --count > 0) {
700 cb.Insert (pos, digitLowerTable [exponent % 10]);
705 return cb.ToString ();
710 internal static string FormatCustom (string format, NumberStore ns, NumberFormatInfo nfi)
712 bool p = ns.Positive;
715 CustomInfo.GetActiveSection (format,ref p, ns.ZeroOnly, ref offset, ref length);
717 return ns.Positive ? "" : nfi.NegativeSign;
721 CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
723 Console.WriteLine("Format : {0}",format);
724 Console.WriteLine("DecimalDigits : {0}",info.DecimalDigits);
725 Console.WriteLine("DecimalPointPos : {0}",info.DecimalPointPos);
726 Console.WriteLine("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
727 Console.WriteLine("IntegerDigits : {0}",info.IntegerDigits);
728 Console.WriteLine("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
729 Console.WriteLine("IntegerHeadPos : {0}",info.IntegerHeadPos);
730 Console.WriteLine("UseExponent : {0}",info.UseExponent);
731 Console.WriteLine("ExponentDigits : {0}",info.ExponentDigits);
732 Console.WriteLine("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
733 Console.WriteLine("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
734 Console.WriteLine("DividePlaces : {0}",info.DividePlaces);
735 Console.WriteLine("Percents : {0}",info.Percents);
736 Console.WriteLine("Permilles : {0}",info.Permilles);
738 StringBuilder sb_int = new StringBuilder(info.IntegerDigits * 2);
739 StringBuilder sb_dec = new StringBuilder(info.DecimalDigits * 2);
740 StringBuilder sb_exp = (info.UseExponent ? new StringBuilder(info.ExponentDigits * 2) : null);
743 if (info.Percents > 0) {
744 ns.Multiply10 (2 * info.Percents);
746 if (info.Permilles > 0) {
747 ns.Multiply10 (3 * info.Permilles);
749 if (info.DividePlaces > 0) {
750 ns.Divide10 (info.DividePlaces);
753 bool expPositive = true;
754 if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
757 while (ns.IntegerDigits > info.IntegerDigits) {
760 if (ns.IntegerDigits == 1 && ns.GetChar (0) == '0')
763 while (ns.IntegerDigits < info.IntegerDigits || (ns.IntegerDigits == info.IntegerDigits && ns.GetChar (0) == '0')) {
768 if (!ns.RoundDecimal (info.DecimalDigits))
773 expPositive = diff <= 0;
774 NumberStore.AppendIntegerStringFromUInt32 (sb_exp, (uint)(diff >= 0 ? diff : -diff));
776 ns.RoundDecimal (info.DecimalDigits);
781 if (info.IntegerDigits != 0 || !ns.CheckZeroOnlyInteger ()) {
782 ns.AppendIntegerString (ns.IntegerDigits, sb_int);
784 /* if (sb_int.Length > info.IntegerDigits) {
786 while (sb_int.Length > info.IntegerDigits && len < sb_int.Length) {
787 if (sb_int [len] == '0')
792 sb_int.Remove (0, len);
795 ns.AppendDecimalString (ns.DecimalDigits, sb_dec);
797 if (info.UseExponent) {
798 if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
801 /*if (sb_int.Length < info.IntegerDigits)
802 sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);*/
804 while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
805 sb_exp.Insert (0, '0');
807 if (expPositive && !info.ExponentNegativeSignOnly)
808 sb_exp.Insert (0, nfi.PositiveSign);
809 else if(!expPositive)
810 sb_exp.Insert (0, nfi.NegativeSign);
812 if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
813 sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
814 if (info.IntegerDigits == info.IntegerHeadSharpDigits && NumberStore.IsZeroOnly (sb_int))
815 sb_int.Remove (0, sb_int.Length);
818 ZeroTrimEnd (sb_dec, true);
819 while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
821 if (sb_dec.Length > info.DecimalDigits)
822 sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
824 return info.Format (format, offset, length, nfi, ns.Positive, sb_int, sb_dec, sb_exp);
827 private class CustomInfo
829 public bool UseGroup = false;
830 public int DecimalDigits = 0;
831 public int DecimalPointPos = -1;
832 public int DecimalTailSharpDigits = 0;
833 public int IntegerDigits = 0;
834 public int IntegerHeadSharpDigits = 0;
835 public int IntegerHeadPos = 0;
836 public bool UseExponent = false;
837 public int ExponentDigits = 0;
838 public int ExponentTailSharpDigits = 0;
839 public bool ExponentNegativeSignOnly = true;
840 public int DividePlaces = 0;
841 public int Percents = 0;
842 public int Permilles = 0;
844 public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
846 int[] lens = new int [3];
850 for (int i = 0; i < format.Length; i++) {
853 if (c == literal || (literal == '\0' && (c == '\"' || c == '\''))) {
861 if (literal == '\0' && format [i] == ';' && (i == 0 || format [i - 1] != '\\')) {
862 lens [index ++] = i - lastPos;
871 length = format.Length;
875 if (positive || zero) {
880 if (lens [0] + 1 < format.Length) {
882 offset = lens [0] + 1;
883 length = format.Length - offset;
893 offset = lens [0] + lens [1] + 2;
894 length = format.Length - offset;
904 offset = lens [0] + 1;
915 offset = lens [0] + lens [1] + 2;
926 offset = lens [0] + 1;
936 throw new ArgumentException ();
939 public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
942 bool integerArea = true;
943 bool decimalArea = false;
944 bool exponentArea = false;
945 bool sharpContinues = true;
947 CustomInfo info = new CustomInfo ();
948 int groupSeparatorCounter = 0;
950 for (int i = offset; i - offset < length; i++) {
953 if (c == literal && c != '\0') {
960 if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
961 exponentArea = false;
962 integerArea = (info.DecimalPointPos < 0);
963 decimalArea = !integerArea;
974 if (c == '\"' || c == '\'') {
979 if (sharpContinues && integerArea)
980 info.IntegerHeadSharpDigits ++;
981 else if (decimalArea)
982 info.DecimalTailSharpDigits ++;
983 else if (exponentArea)
984 info.ExponentTailSharpDigits ++;
989 sharpContinues = false;
991 info.DecimalTailSharpDigits = 0;
992 else if (exponentArea)
993 info.ExponentTailSharpDigits = 0;
995 if (info.IntegerHeadPos == -1)
996 info.IntegerHeadPos = i;
999 info.IntegerDigits ++;
1000 if (groupSeparatorCounter > 0)
1001 info.UseGroup = true;
1002 groupSeparatorCounter = 0;
1003 } else if (decimalArea) {
1004 info.DecimalDigits ++;
1005 } else if (exponentArea) {
1006 info.ExponentDigits ++;
1011 if (info.UseExponent)
1014 info.UseExponent = true;
1015 integerArea = false;
1016 decimalArea = false;
1017 exponentArea = true;
1018 if (i + 1 - offset < length) {
1019 char nc = format [i + 1];
1021 info.ExponentNegativeSignOnly = false;
1022 if (nc == '+' || nc == '-') {
1024 } else if (nc != '0' && nc != '#') {
1025 info.UseExponent = false;
1026 if (info.DecimalPointPos < 0)
1034 integerArea = false;
1036 exponentArea = false;
1037 if (info.DecimalPointPos == -1)
1038 info.DecimalPointPos = i;
1047 if (integerArea && info.IntegerDigits > 0)
1048 groupSeparatorCounter ++;
1055 if (info.ExponentDigits == 0)
1056 info.UseExponent = false;
1058 info.IntegerHeadSharpDigits = 0;
1060 if (info.DecimalDigits == 0)
1061 info.DecimalPointPos = -1;
1063 info.DividePlaces += groupSeparatorCounter * 3;
1068 public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
1070 StringBuilder sb = new StringBuilder ();
1071 char literal = '\0';
1072 bool integerArea = true;
1073 bool decimalArea = false;
1074 int intSharpCounter = 0;
1075 int sb_int_index = 0;
1076 int sb_dec_index = 0;
1078 int[] groups = nfi.NumberGroupSizes;
1079 string groupSeparator = nfi.NumberGroupSeparator;
1080 int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0, fraction = 0;
1081 if (UseGroup && groups.Length > 0) {
1082 intLen = sb_int.Length;
1083 for (int i = 0; i < groups.Length; i++) {
1084 total += groups [i];
1085 if (total <= intLen)
1088 groupSize = groups [groupIndex];
1089 fraction = intLen > total ? intLen - total : 0;
1090 if (groupSize == 0) {
1091 while (groupIndex >= 0 && groups [groupIndex] == 0)
1094 groupSize = fraction > 0 ? fraction : groups [groupIndex];
1096 if (fraction == 0) {
1097 counter = groupSize;
1099 groupIndex += fraction / groupSize;
1100 counter = fraction % groupSize;
1102 counter = groupSize;
1110 for (int i = offset; i - offset < length; i++) {
1111 char c = format [i];
1113 if (c == literal && c != '\0') {
1117 if (literal != '\0') {
1125 if (i - offset < length)
1126 sb.Append (format [i]);
1130 if (c == '\"' || c == '\'') {
1139 if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
1140 while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
1141 sb.Append (sb_int[ sb_int_index++]);
1142 if (UseGroup && --intLen > 0 && --counter == 0) {
1143 sb.Append (groupSeparator);
1144 if (--groupIndex < groups.Length && groupIndex >= 0)
1145 groupSize = groups [groupIndex];
1146 counter = groupSize;
1150 } else if (decimalArea) {
1151 if (sb_dec_index < sb_dec.Length)
1152 sb.Append (sb_dec [sb_dec_index++]);
1160 if (sb_exp == null || !UseExponent) {
1169 for (q = i + 1; q - offset < length; q++) {
1170 if (format [q] == '0') {
1174 if (q == i + 1 && (format [q] == '+' || format [q] == '-')) {
1184 integerArea = (DecimalPointPos < 0);
1185 decimalArea = !integerArea;
1195 if (DecimalPointPos == i) {
1196 if (DecimalDigits > 0) {
1197 while (sb_int_index < sb_int.Length)
1198 sb.Append (sb_int [sb_int_index++]);
1200 if (sb_dec.Length > 0)
1201 sb.Append (nfi.NumberDecimalSeparator);
1203 integerArea = false;
1209 sb.Append (nfi.PercentSymbol);
1212 sb.Append (nfi.PerMilleSymbol);
1221 sb.Insert (0, nfi.NegativeSign);
1223 return sb.ToString ();
1229 #region Internal structures
1230 internal struct NumberStore
1237 int _defMaxPrecision;
1242 static uint [] IntList = new uint [] {
1255 static ulong [] ULongList = new ulong [] {
1274 1000000000000000000,
1275 10000000000000000000,
1278 #region Constructors
1279 public NumberStore (long value)
1281 _infinity = _NaN = false;
1283 _defMaxPrecision = _defPrecision = 19;
1284 _positive = value >= 0;
1287 _digits = new byte []{0};
1292 ulong v = (ulong)(_positive ? value : -value);
1304 else if (v < 100000)
1306 else if (v < 1000000)
1308 else if (v < 10000000)
1310 else if (v < 100000000)
1312 else if (v < 1000000000)
1314 else if (v < 10000000000)
1316 else if (v < 100000000000)
1318 else if (v < 1000000000000)
1320 else if (v < 10000000000000)
1322 else if (v < 100000000000000)
1324 else if (v < 1000000000000000)
1326 else if (v < 10000000000000000)
1328 else if (v < 100000000000000000)
1330 else if (v < 1000000000000000000)
1335 _digits = new byte [i + 1];
1337 ulong n = v / ULongList [i];
1338 _digits [j++] = (byte)n;
1339 v -= ULongList [i--] * n;
1342 _decPointPos = _digits.Length;
1344 public NumberStore (int value)
1346 _infinity = _NaN = false;
1348 _defMaxPrecision = _defPrecision = 10;
1349 _positive = value >= 0;
1352 _digits = new byte []{0};
1357 uint v = (uint)(_positive ? value : -value);
1369 else if (v < 100000)
1371 else if (v < 1000000)
1373 else if (v < 10000000)
1375 else if (v < 100000000)
1377 else if (v < 1000000000)
1382 _digits = new byte [i + 1];
1384 uint n = v / IntList [i];
1385 _digits [j++] = (byte)n;
1386 v -= IntList [i--] * n;
1389 _decPointPos = _digits.Length;
1391 public NumberStore (short value) : this ((int)value)
1394 _defMaxPrecision = _defPrecision = 5;
1396 public NumberStore (sbyte value) : this ((int)value)
1399 _defMaxPrecision = _defPrecision = 3;
1402 public NumberStore (ulong value)
1404 _infinity = _NaN = false;
1406 _defMaxPrecision = _defPrecision = 20;
1410 _digits = new byte []{0};
1419 else if (value < 100)
1421 else if (value < 1000)
1423 else if (value < 10000)
1425 else if (value < 100000)
1427 else if (value < 1000000)
1429 else if (value < 10000000)
1431 else if (value < 100000000)
1433 else if (value < 1000000000)
1435 else if (value < 10000000000)
1437 else if (value < 100000000000)
1439 else if (value < 1000000000000)
1441 else if (value < 10000000000000)
1443 else if (value < 100000000000000)
1445 else if (value < 1000000000000000)
1447 else if (value < 10000000000000000)
1449 else if (value < 100000000000000000)
1451 else if (value < 1000000000000000000)
1453 else if (value < 10000000000000000000)
1458 _digits = new byte [i + 1];
1460 ulong n = value / ULongList [i];
1461 _digits [j++] = (byte)n;
1462 value -= ULongList [i--] * n;
1465 _decPointPos = _digits.Length;
1467 public NumberStore (uint value)
1469 _infinity = _NaN = false;
1472 _defMaxPrecision = _defPrecision = 10;
1475 _digits = new byte []{0};
1484 else if (value < 100)
1486 else if (value < 1000)
1488 else if (value < 10000)
1490 else if (value < 100000)
1492 else if (value < 1000000)
1494 else if (value < 10000000)
1496 else if (value < 100000000)
1498 else if (value < 1000000000)
1503 _digits = new byte [i + 1];
1505 uint n = value / IntList [i];
1506 _digits [j++] = (byte)n;
1507 value -= IntList [i--] * n;
1510 _decPointPos = _digits.Length;
1512 public NumberStore (ushort value) : this ((uint)value)
1515 _defMaxPrecision = _defPrecision = 5;
1517 public NumberStore (byte value) : this ((uint)value)
1520 _defMaxPrecision = _defPrecision = 3;
1523 public NumberStore(double value)
1528 _defMaxPrecision = _defPrecision + 2;
1530 if (double.IsNaN (value) || double.IsInfinity (value)) {
1531 _NaN = double.IsNaN (value);
1532 _infinity = double.IsInfinity (value);
1533 _positive = value > 0;
1537 _NaN = _infinity = false;
1540 long bits = BitConverter.DoubleToInt64Bits (value);
1541 _positive = (bits >= 0);
1542 int e = (int) ((bits >> 52) & 0x7ffL);
1543 long m = bits & 0xfffffffffffffL;
1545 if (e == 0 && m == 0) {
1547 _digits = new byte []{0};
1554 } else if (e != 0) {
1561 while ((m & 1) == 0) {
1569 byte[] temp = new byte [56];
1570 for (int i = temp.Length - 1; i >= 0; i--, length++) {
1571 temp [i] = (byte)(mt % 10);
1577 _decPointPos = temp.Length - 1;
1580 for (int i = 0; i < e; i++) {
1581 if (MultiplyBy (ref temp, ref length, 2)) {
1586 for (int i = 0; i < -e; i++) {
1587 if (MultiplyBy (ref temp, ref length, 5)) {
1596 for (int i = 0; i < temp.Length; i++)
1597 if (temp [i] != 0) {
1598 _decPointPos -= i - 1;
1599 _digits = new byte [temp.Length - i];
1600 for (int q = i; q < temp.Length; q++) {
1601 _digits [q - i] = temp [q];
1603 ulv = ulv * 10 + temp [q];
1610 RoundEffectiveDigits (17, true, true);
1612 public NumberStore(float value)
1617 _defMaxPrecision = _defPrecision + 2;
1619 if (float.IsNaN (value) || float.IsInfinity (value)) {
1620 _NaN = float.IsNaN (value);
1621 _infinity = float.IsInfinity (value);
1622 _positive = value > 0;
1626 _infinity = _NaN = false;
1628 long bits = BitConverter.DoubleToInt64Bits (value);
1629 _positive = (bits >= 0);
1630 int e = (int) ((bits >> 52) & 0x7ffL);
1631 long m = bits & 0xfffffffffffffL;
1633 if (e == 0 && m == 0) {
1635 _digits = new byte []{0};
1642 } else if (e != 0) {
1649 while ((m & 1) == 0) {
1657 byte[] temp = new byte [26];
1658 for (int i = temp.Length - 1; i >= 0; i--, length++) {
1659 temp [i] = (byte)(mt % 10);
1665 _decPointPos = temp.Length - 1;
1668 for (int i = 0; i < e; i++) {
1669 if (MultiplyBy (ref temp, ref length, 2)) {
1674 for (int i = 0; i < -e; i++) {
1675 if (MultiplyBy (ref temp, ref length, 5)) {
1684 for (int i = 0; i < temp.Length; i++)
1685 if (temp [i] != 0) {
1686 _decPointPos -= i - 1;
1687 _digits = new byte [temp.Length - i];
1688 for (int q = i; q < temp.Length; q++) {
1689 _digits [q - i] = temp [q];
1691 ulv = ulv * 10 + temp [q];
1698 RoundEffectiveDigits (9, true, true);
1701 internal bool MultiplyBy (ref byte[] buffer,ref int length, int amount)
1705 int start = buffer.Length - length - 1;
1706 if (start < 0) start = 0;
1708 for (int i = buffer.Length - 1; i > start; i--) {
1709 ret = buffer [i] * amount + mod;
1711 buffer [i] = (byte)(ret % 10);
1715 length = buffer.Length - start;
1718 buffer [0] = (byte)mod;
1719 Array.Copy (buffer, 0, buffer, 1, buffer.Length - 1);
1724 buffer [start] = (byte)mod;
1732 #region Public Property
1735 get { return _NaN; }
1737 public bool IsInfinity {
1738 get { return _infinity; }
1740 public int DecimalPointPosition {
1741 get { return _decPointPos; }
1743 public bool Positive {
1744 get { return _positive; }
1745 set { _positive = value;}
1747 public int DefaultPrecision {
1748 get { return _defPrecision; }
1750 public int DefaultMaxPrecision {
1751 get { return _defMaxPrecision; }
1753 public int DefaultByteSize {
1754 get { return _defByteSize; }
1756 public bool HasDecimal {
1757 get { return _digits.Length > _decPointPos; }
1759 public int IntegerDigits {
1760 get { return _decPointPos > 0 ? _decPointPos : 1; }
1762 public int DecimalDigits {
1763 get { return HasDecimal ? _digits.Length - _decPointPos : 0; }
1765 public bool IsFloatingSource {
1766 get { return _defPrecision == 15 || _defPrecision == 7; }
1768 public bool ZeroOnly {
1770 for (int i = 0; i < _digits.Length; i++)
1771 if (_digits [i] != 0)
1778 #region Public Method
1781 public bool RoundPos (int pos)
1783 return RoundPos (pos, true);
1785 public bool RoundPos (int pos, bool carryFive)
1789 if (_decPointPos <= 0)
1790 pos = pos - _decPointPos - 1;
1792 if (pos >= _digits.Length)
1796 _digits = new byte [1];
1803 for (int i = pos; i >= 0; i--) {
1804 RoundHelper (i, carryFive, ref carry);
1810 byte[] temp = new byte [_digits.Length + 1];
1811 _digits.CopyTo (temp, 1);
1818 for (int i = pos; i < _digits.Length; i++)
1820 TrimDecimalEndZeros ();
1824 public bool RoundDecimal (int decimals)
1826 return RoundDecimal (decimals, true);
1828 public bool RoundDecimal (int decimals, bool carryFive)
1832 decimals += _decPointPos;
1834 if (!HasDecimal || decimals >= _digits.Length)
1838 _digits = new byte [1];
1845 for (int i = decimals; i >= 0; i--) {
1846 RoundHelper (i, carryFive, ref carry);
1852 byte[] temp = new byte [_digits.Length + 1];
1853 _digits.CopyTo (temp, 1);
1860 for (int i = decimals; i < _digits.Length; i++)
1862 TrimDecimalEndZeros ();
1866 void RoundHelper (int index, bool carryFive, ref bool carry)
1869 if (_digits [index] == 9) {
1871 _digits [index] = 0;
1876 } else if (_digits [index] >= (carryFive ? 5 : 6)) {
1880 public bool RoundEffectiveDigits (int digits)
1882 return RoundEffectiveDigits (digits, true, true);
1884 public bool RoundEffectiveDigits (int digits, bool carryFive, bool carryEven)
1888 if (digits >= _digits.Length || digits < 0)
1891 if (digits + 1 < _digits.Length && _digits [digits + 1] == 5 && _digits [digits] % 2 == (carryEven ? 0 : 1))
1894 for (int i = digits; i >= 0; i--) {
1895 RoundHelper (i, carryFive, ref carry);
1901 byte[] temp = new byte [_digits.Length + 1];
1902 _digits.CopyTo (temp, 1);
1909 for (int i = digits; i < _digits.Length; i++)
1911 TrimDecimalEndZeros ();
1918 public void TrimDecimalEndZeros ()
1921 for (int i = _digits.Length - 1; i >= 0; i --) {
1922 if (_digits [i] != 0)
1928 byte[] temp = new byte [_digits.Length - len];
1929 Array.Copy (_digits, 0, temp, 0, temp.Length);
1933 public void TrimIntegerStartZeros ()
1935 if (_decPointPos < 0 && _decPointPos >= _digits.Length)
1939 for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
1940 if (_digits [i] != 0)
1945 if (len == _decPointPos)
1948 if (len == _digits.Length) {
1949 _digits = new byte [1];
1953 } else if (len > 0) {
1954 byte[] temp = new byte [_digits.Length - len];
1955 Array.Copy (_digits, len, temp, 0, temp.Length);
1957 _decPointPos -= len;
1964 public void AppendIntegerString (int minLength, StringBuilder cb)
1966 if (IntegerDigits == 0) {
1967 cb.Append ('0', minLength);
1970 if (_decPointPos <= 0) {
1971 cb.Append ('0', minLength);
1975 if (_decPointPos < minLength)
1976 cb.Append ('0', minLength - _decPointPos);
1978 for (int i = 0; i < _decPointPos; i++) {
1979 if (i < _digits.Length)
1980 cb.Append ((char)('0' + _digits [i]));
1985 public void AppendIntegerStringWithGroupSeparator (StringBuilder sb, int[] groups, string groupSeparator)
1987 if (_decPointPos <= 0) {
1992 int intLen = IntegerDigits;
1995 for (int i = 0; i < groups.Length; i++) {
1996 total += groups [i];
1997 if (total <= intLen)
2001 if (groups.Length > 0 && total > 0) {
2003 int groupSize = groups [groupIndex];
2004 int fraction = intLen > total ? intLen - total : 0;
2005 if (groupSize == 0) {
2006 while (groupIndex >= 0 && groups [groupIndex] == 0)
2009 groupSize = fraction > 0 ? fraction : groups [groupIndex];
2011 if (fraction == 0) {
2012 counter = groupSize;
2014 groupIndex += fraction / groupSize;
2015 counter = fraction % groupSize;
2017 counter = groupSize;
2022 for (int i = 0; i < _decPointPos; i++) {
2023 if (i < _digits.Length) {
2024 sb.Append ((char)('0' + _digits [i]));
2029 if (i < intLen - 1 && --counter == 0) {
2030 sb.Append (groupSeparator);
2031 if (--groupIndex < groups.Length && groupIndex >= 0)
2032 groupSize = groups [groupIndex];
2033 counter = groupSize;
2037 for (int i = 0; i < _decPointPos; i++) {
2038 if (i < _digits.Length) {
2039 sb.Append ((char)('0' + _digits [i]));
2049 public string GetDecimalString (int precision)
2052 return new string ('0', precision);
2054 StringBuilder sb = new StringBuilder (precision);
2055 for (int i = _decPointPos; i < _digits.Length && i < precision + _decPointPos; i++) {
2057 sb.Append ((char)('0' + _digits [i]));
2061 if (sb.Length < precision)
2062 sb.Append ('0', precision - sb.Length);
2063 else if (sb.Length > precision)
2064 sb.Remove (0, precision);
2065 return sb.ToString ();
2068 public void AppendDecimalString (int precision, StringBuilder cb)
2071 cb.Append ('0', precision);
2075 int i = _decPointPos;
2076 for (; i < _digits.Length && i < precision + _decPointPos; i++) {
2078 cb.Append ((char)('0' + _digits [i]));
2085 cb.Append ('0', precision - i);
2090 public bool CheckZeroOnlyInteger ()
2092 for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
2093 if (_digits [i] != 0)
2098 public void Multiply10 (int count)
2103 _decPointPos += count;
2105 TrimIntegerStartZeros ();
2107 public void Divide10 (int count)
2112 _decPointPos -= count;
2114 public override string ToString()
2116 StringBuilder sb = new StringBuilder ();
2117 AppendIntegerString (IntegerDigits, sb);
2120 AppendDecimalString (DecimalDigits, sb);
2122 return sb.ToString ();
2124 public char GetChar (int pos)
2126 if (_decPointPos <= 0)
2127 pos += _decPointPos - 1;
2129 if (pos < 0 || pos >= _digits.Length)
2132 return (char)('0' + _digits [pos]);
2134 public byte GetDigitByte (int pos)
2136 if (_decPointPos <= 0)
2137 pos += _decPointPos - 1;
2139 if (pos < 0 || pos >= _digits.Length)
2142 return _digits [pos];
2144 public NumberStore GetClone ()
2146 NumberStore ns = new NumberStore ();
2148 ns._decPointPos = this._decPointPos;
2149 ns._defMaxPrecision = this._defMaxPrecision;
2150 ns._defPrecision = this._defPrecision;
2151 ns._digits = (byte[])this._digits.Clone ();
2152 ns._infinity = this._infinity;
2153 ns._NaN = this._NaN;
2154 ns._positive = this._positive;
2158 public int GetDecimalPointPos ()
2160 return _decPointPos;
2162 public void SetDecimalPointPos (int dp)
2170 #region Public Static Method
2171 public static bool IsZeroOnly (StringBuilder sb)
2173 for (int i = 0; i < sb.Length; i++)
2174 if (char.IsDigit (sb [i]) && sb [i] != '0')
2178 public static void AppendIntegerStringFromUInt32 (StringBuilder sb, uint v)
2181 throw new ArgumentException ();
2185 if (v >= 1000000000)
2187 else if (v >= 100000000)
2189 else if (v >= 10000000)
2191 else if (v >= 1000000)
2193 else if (v >= 100000)
2195 else if (v >= 10000)
2206 uint n = v / IntList [i];
2207 sb.Append (NumberFormatter.digitLowerTable [n]);
2208 v -= IntList [i--] * n;
2213 internal struct CharBuffer
2218 public CharBuffer (int capacity)
2220 buffer = new char [capacity];
2224 void AllocateBuffer (int size)
2226 size = size > buffer.Length * 2 ? size : buffer.Length * 2;
2227 char[] newBuffer = new char [size];
2228 offset += size - buffer.Length;
2229 Array.Copy (buffer, 0, newBuffer, size - buffer.Length, buffer.Length);
2233 void CheckInsert (int length)
2235 if (offset - length < 0) {
2236 AllocateBuffer (buffer.Length + length - offset);
2240 public void InsertToFront (char c)
2243 buffer [--offset] = c;
2246 public void InsertToFront (char c, int repeat)
2248 CheckInsert (repeat);
2249 while (repeat-- > 0) {
2250 buffer [--offset] = c;
2254 public char this [int index]
2257 return buffer [offset + index];
2261 public override string ToString()
2263 if (offset == buffer.Length)
2266 return new string (buffer, offset, buffer.Length - offset);
2270 get { return buffer.Length - offset; }