2007-11-12 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / corlib / System / NumberFormatter.cs
1 //
2 // System.NumberFormatter.cs
3 //
4 // Author:
5 //   Kazuki Oikawa (kazuki@panicode.com)
6 //
7
8 using System.Collections;
9 using System.Globalization;
10 using System.Text;
11
12 namespace System
13 {
14         class NumberFormatter
15         {
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'};
18
19                 #region NumberToString
20                 public static string NumberToString (string format, sbyte value, NumberFormatInfo nfi)
21                 {
22                         char specifier;
23                         int precision;
24                         bool custom;
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);
29                 }
30                 public static string NumberToString (string format, byte value, NumberFormatInfo nfi)
31                 {
32                         char specifier;
33                         int precision;
34                         bool custom;
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);
39                 }
40                 public static string NumberToString (string format, ushort value, NumberFormatInfo nfi)
41                 {
42                         char specifier;
43                         int precision;
44                         bool custom;
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);
49                 }
50                 public static string NumberToString (string format, short value, NumberFormatInfo nfi)
51                 {
52                         char specifier;
53                         int precision;
54                         bool custom;
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);
59                 }
60                 public static string NumberToString (string format, uint value, NumberFormatInfo nfi)
61                 {
62                         char specifier;
63                         int precision;
64                         bool custom;
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);
69                 }
70                 public static string NumberToString (string format, int value, NumberFormatInfo nfi)
71                 {
72                         char specifier;
73                         int precision;
74                         bool custom;
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);
79                 }
80                 public static string NumberToString (string format, ulong value, NumberFormatInfo nfi)
81                 {
82                         char specifier;
83                         int precision;
84                         bool custom;
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);
89                 }
90                 public static string NumberToString (string format, long value, NumberFormatInfo nfi)
91                 {
92                         char specifier;
93                         int precision;
94                         bool custom;
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);
99                 }
100                 public static string NumberToString (string format, float value, NumberFormatInfo nfi)
101                 {
102                         char specifier;
103                         int precision;
104                         bool custom;
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);
108                 }
109                 public static string NumberToString (string format, double value, NumberFormatInfo nfi)
110                 {
111                         char specifier;
112                         int precision;
113                         bool custom;
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);
117                 }
118                 public static string NumberToString (string format, decimal value, NumberFormatInfo nfi)
119                 {
120                         char specifier;
121                         int precision;
122                         bool custom;
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);
126                 }
127                 public static string NumberToString (string format, NumberStore ns, NumberFormatInfo nfi, char specifier, int precision, bool custom)
128                 {
129                         if (ns.IsNaN) {
130                                 return nfi.NaNSymbol;
131                         }
132                         if (ns.IsInfinity) {
133                                 if (ns.Positive)
134                                         return nfi.PositiveInfinitySymbol;
135                                 else
136                                         return nfi.NegativeInfinitySymbol;
137                         }
138
139                         if (nfi == null) 
140                                 nfi = NumberFormatInfo.GetInstance (null);
141                         
142                         if (custom){
143                                 if (ns.IsFloatingSource)
144                                         ns.RoundEffectiveDigits (ns.DefaultPrecision);
145                                 return FormatCustom (format, ns, nfi);
146                         }
147
148                         if (ns.IsFloatingSource) {
149                                 switch(specifier) {
150                                 case 'p':
151                                 case 'P':
152                                 case 'c':
153                                 case 'C':
154                                 case 'f':
155                                 case 'F':
156                                 case 'N':
157                                 case 'n':
158                                         ns.RoundEffectiveDigits (ns.DefaultPrecision);
159                                         break;
160                                 case 'g':
161                                 case 'G':
162                                         if (precision <= 0)
163                                                 ns.RoundEffectiveDigits (ns.DefaultPrecision, ns.IsBankerApplicable, true);
164                                         else
165                                                 ns.RoundEffectiveDigits (precision);
166                                         break;
167                                 case 'r':
168                                 case 'R':
169                                         ns.RoundEffectiveDigits (ns.DefaultMaxPrecision);
170
171                                         // FIXME: it is a quick workaround for non-roundtrip issue (bug #320433).
172                                         string orgStr = FormatGeneral (ns, ns.DefaultPrecision, nfi, true, true);
173                                         double orgValue = double.Parse (orgStr);
174                                         NumberStore tmpNS = new NumberStore (orgValue);
175                                         tmpNS.RoundEffectiveDigits (tmpNS.DefaultMaxPrecision);
176                                         tmpNS.RoundEffectiveDigits (tmpNS.DefaultMaxPrecision - 1);
177                                         string tmpStr = FormatGeneral (tmpNS, ns.DefaultPrecision, nfi, true, true);
178                                         double tmpValue = double.Parse (tmpStr);
179                                         if (orgValue == tmpValue && orgStr.Length - tmpStr.Length > 1)
180                                                 ns = tmpNS;
181
182                                         break;
183                                 default:
184                                         if (precision > ns.DefaultPrecision)
185                                                 ns.RoundEffectiveDigits (precision + 1);
186                                         else
187                                                 ns.RoundEffectiveDigits (ns.DefaultPrecision + 1);
188                                         break;
189                                 }
190                         }
191
192                         switch(specifier) {
193                         case 'c':
194                         case 'C':
195                                 return FormatCurrency (ns, precision, nfi);
196                         case 'd':
197                         case 'D':
198                                 return FormatDecimal (ns, precision, nfi);
199                         case 'e':
200                         case 'E':
201                                 return FormatExponential (ns, precision, nfi, specifier == 'E');
202                         case 'f': 
203                         case 'F':
204                                 return FormatFixedPoint (ns, precision, nfi);
205                         case 'g':
206                         case 'G':
207                                 if (ns.IsFloatingSource || ns.IsDecimalSource || precision != -1)
208                                         return FormatGeneral (ns, precision, nfi, specifier == 'G', false);
209                                 return FormatDecimal (ns, precision, nfi);
210                         case 'n':
211                         case 'N':
212                                 return FormatNumber (ns, precision, nfi);
213                         case 'p':
214                         case 'P':
215                                 return FormatPercent (ns, precision, nfi);
216                         case 'r':
217                         case 'R':
218                                 if (ns.IsFloatingSource) {
219                                         return FormatGeneral (ns, ns.DefaultPrecision, nfi, true, true);
220                                 } else {
221                                         throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
222                                 }
223                         default: 
224                                 throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
225                         }       
226                 }
227                 #endregion
228
229                 #region BasicParser
230                 private static void ParseBasicFormat (string format, out char specifier, out int precision, out bool custom)
231                 {
232                         if (format == null || format.Length == 0) {
233                                 precision = -1;
234                                 specifier = 'G';
235                                 custom = false;
236                                 return;
237                         }
238
239                         precision = -1;
240                         specifier = format[0];
241                         custom = false;
242
243                         if (Char.IsLetter (specifier)) {
244                                 if (format.Length == 1)
245                                         return;
246
247                                 bool flag = true;
248                                 precision = 0;
249                                 for (int i = 1; i < format.Length; i++) {
250                                         char c = format [i];
251                                         if (char.IsDigit (c)) {
252                                                 precision = precision * 10 + (c - '0');
253                                                 if (precision > 99) {
254                                                         flag = false;
255                                                         break;
256                                                 }
257                                         }
258                                         else {
259                                                 flag = false;
260                                                 break;
261                                         }
262                                 }
263                                 if (flag)
264                                         return;
265                         }
266
267                         custom = true;
268                         return;
269                 }       
270
271                 #endregion
272
273                 #region Helpers
274                 private static void ZeroTrimEnd (StringBuilder sb)
275                 {
276                         ZeroTrimEnd (sb, false);
277                 }
278                 private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
279                 {
280                         int len = 0;
281                         for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i --) {
282                                 if (sb [i] != '0')
283                                         break;
284                                 len ++;
285                         }
286
287                         if (len > 0)
288                                 sb.Remove (sb.Length - len, len);
289                 }
290                 #endregion
291
292                 #region Basic
293                 internal static string FormatCurrency (NumberStore ns, int precision, NumberFormatInfo nfi)
294                 {
295                         precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
296                         ns.RoundDecimal (precision);
297                         StringBuilder sb = new StringBuilder (ns.IntegerDigits * 2 + precision * 2 + 16);
298                         bool needNegativeSign = !ns.Positive && !ns.ZeroOnly;
299
300                         if (!needNegativeSign) {
301                                 switch (nfi.CurrencyPositivePattern) {
302                                 case 0:
303                                         sb.Append (nfi.CurrencySymbol);
304                                         break;
305                                 case 2:
306                                         sb.Append (nfi.CurrencySymbol);
307                                         sb.Append (' ');
308                                         break;
309                                 }
310                         } else {
311                                 switch (nfi.CurrencyNegativePattern) {
312                                 case 0:
313                                         sb.Append ('(');
314                                         sb.Append (nfi.CurrencySymbol);
315                                         break;
316                                 case 1:
317                                         sb.Append (nfi.NegativeSign);
318                                         sb.Append (nfi.CurrencySymbol);
319                                         break;
320                                 case 2:
321                                         sb.Append (nfi.CurrencySymbol);
322                                         sb.Append (nfi.NegativeSign);
323                                         break;
324                                 case 3:
325                                         sb.Append (nfi.CurrencySymbol);
326                                         break;
327                                 case 4:
328                                         sb.Append ('(');
329                                         break;
330                                 case 5:
331                                         sb.Append (nfi.NegativeSign);
332                                         break;
333                                 case 8:
334                                         sb.Append (nfi.NegativeSign);
335                                         break;
336                                 case 9:
337                                         sb.Append (nfi.NegativeSign);
338                                         sb.Append (nfi.CurrencySymbol);
339                                         sb.Append (' ');                                        
340                                         break;
341                                 case 11:
342                                         sb.Append (nfi.CurrencySymbol);
343                                         sb.Append (' ');
344                                         break;
345                                 case 12:
346                                         sb.Append (nfi.CurrencySymbol);
347                                         sb.Append (' ');
348                                         sb.Append (nfi.NegativeSign);                                   
349                                         break;
350                                 case 14:
351                                         sb.Append ('(');
352                                         sb.Append (nfi.CurrencySymbol);
353                                         sb.Append (' ');
354                                         break;
355                                 case 15:
356                                         sb.Append ('(');
357                                         break;
358                                 }
359                         }
360
361                         ns.AppendIntegerStringWithGroupSeparator (sb, nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);
362
363                         if (precision > 0)
364                         {
365                                 sb.Append (nfi.CurrencyDecimalSeparator);
366                                 ns.AppendDecimalString (precision, sb);
367                         }
368
369                         if (!needNegativeSign) {
370                                 switch (nfi.CurrencyPositivePattern) {
371                                 case 1:
372                                         sb.Append (nfi.CurrencySymbol);
373                                         break;
374                                 case 3:
375                                         sb.Append (' ');
376                                         sb.Append (nfi.CurrencySymbol);
377                                         break;
378                                 }
379                         } else {
380                                 switch (nfi.CurrencyNegativePattern) {
381                                 case 0:
382                                         sb.Append (')');
383                                         break;
384                                 case 3:
385                                         sb.Append (nfi.NegativeSign);
386                                         break;
387                                 case 4:
388                                         sb.Append (nfi.CurrencySymbol);
389                                         sb.Append (')');
390                                         break;
391                                 case 5:
392                                         sb.Append (nfi.CurrencySymbol);
393                                         break;
394                                 case 6:
395                                         sb.Append (nfi.NegativeSign);
396                                         sb.Append (nfi.CurrencySymbol);
397                                         break;
398                                 case 7:
399                                         sb.Append (nfi.CurrencySymbol);
400                                         sb.Append (nfi.NegativeSign);
401                                         break;
402                                 case 8:
403                                         sb.Append (' ');
404                                         sb.Append (nfi.CurrencySymbol);
405                                         break;
406                                 case 10:
407                                         sb.Append (' ');
408                                         sb.Append (nfi.CurrencySymbol);
409                                         sb.Append (nfi.NegativeSign);
410                                         break;
411                                 case 11:
412                                         sb.Append (nfi.NegativeSign);
413                                         break;
414                                 case 13:
415                                         sb.Append (nfi.NegativeSign);
416                                         sb.Append (' ');
417                                         sb.Append (nfi.CurrencySymbol);
418                                         break;
419                                 case 14:
420                                         sb.Append (')');
421                                         break;
422                                 case 15:
423                                         sb.Append (' ');
424                                         sb.Append (nfi.CurrencySymbol);
425                                         sb.Append (')');
426                                         break;
427                                 }
428                         }
429
430                         return sb.ToString ();
431                 }
432                 internal static string FormatDecimal (NumberStore ns, int precision, NumberFormatInfo nfi)
433                 {
434                         if (ns.IsFloatingSource || ns.IsDecimalSource)
435                                 throw new FormatException ();
436
437                         precision = precision > 0 ? precision : 1;
438                         precision = ns.IntegerDigits > precision ? ns.IntegerDigits : precision;
439
440                         StringBuilder sb = new StringBuilder (precision + nfi.NegativeSign.Length);
441
442                         if (!ns.Positive && !ns.CheckZeroOnlyInteger ()) {
443                                 sb.Append (nfi.NegativeSign);
444                         }
445
446                         ns.AppendIntegerString (precision, sb);
447
448                         return sb.ToString ();
449                 }
450                 internal static string FormatFixedPoint (NumberStore ns, int precision, NumberFormatInfo nfi)
451                 {
452                         precision = precision >= 0 ? precision : nfi.NumberDecimalDigits;
453                         ns.RoundDecimal (precision);
454
455                         StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + nfi.NumberDecimalSeparator.Length);
456
457                         if (!ns.Positive && !ns.ZeroOnly)
458                                 cb.Append (nfi.NegativeSign);
459
460                         ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
461
462                         if (precision > 0) {
463                                 cb.Append (nfi.NumberDecimalSeparator);
464                                 ns.AppendDecimalString (precision, cb);
465                         }
466
467                         return cb.ToString ();
468                 }
469
470                 internal static string FormatGeneral (NumberStore ns)
471                 {
472                         return FormatGeneral (ns, -1, NumberFormatInfo.CurrentInfo, true, false);
473                 }
474                 internal static string FormatGeneral (NumberStore ns, IFormatProvider provider)
475                 {
476                         return FormatGeneral (ns, -1, NumberFormatInfo.GetInstance (provider), true, false);
477                 }
478                 private static string FormatGeneral (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper, bool roundtrip)
479                 {
480                         if (ns.ZeroOnly)
481                                 return "0";
482
483                         precision = precision > 0 ? precision : ns.DefaultPrecision;
484
485                         int exponent = 0;
486                         bool expMode = (ns.IsDecimalSource && precision == ns.DefaultPrecision ? false : (ns.IntegerDigits > precision || ns.DecimalPointPosition <= -4));
487                         if (expMode) {
488                                 while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
489                                         if (ns.DecimalPointPosition > 1) {
490                                                 ns.Divide10 (1);
491                                                 exponent ++;
492                                         } else {
493                                                 ns.Multiply10 (1);
494                                                 exponent --;
495                                         }
496                                 }
497                         }
498
499                         precision = precision < ns.DefaultPrecision + 2 ? (precision < ns.DefaultMaxPrecision ? precision : ns.DefaultMaxPrecision) : ns.DefaultPrecision + 2;
500                         StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + 16);
501                         if (expMode) {
502                                 if (ns.RoundDecimal (precision - 1)) {
503                                         ns.Divide10 (1);
504                                         exponent ++;
505                                 }
506                         } else if (!roundtrip) {
507                                 if (ns.IsDecimalSource)
508                                         ns.RoundPos (precision);
509                                 else
510                                         ns.RoundDecimal (precision, true, false);
511                         }
512
513                         if (!ns.Positive) {
514                                 cb.Append (nfi.NegativeSign);
515                         }
516
517                         ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
518
519                         if (ns.DecimalDigits > 0) {
520                                 cb.Append (nfi.NumberDecimalSeparator);
521                                 ns.AppendDecimalString (ns.DecimalDigits, cb);
522                         }
523
524                         if (expMode) {
525                                 if (upper)
526                                         cb.Append ('E');
527                                 else
528                                         cb.Append ('e');
529
530                                 if (exponent >= 0)
531                                         cb.Append (nfi.PositiveSign);
532                                 else {
533                                         cb.Append (nfi.NegativeSign);
534                                         exponent = -exponent;
535                                 }
536
537                                 if (exponent == 0) {
538                                         cb.Append ('0', 2);
539                                 } else if (exponent < 10) {
540                                         cb.Append ('0');
541                                         cb.Append (digitLowerTable [exponent]);
542                                 } else if (exponent < 100) {
543                                         cb.Append (digitLowerTable [exponent / 10 % 10]);
544                                         cb.Append (digitLowerTable [exponent % 10]);
545                                 } else if (exponent < 1000) {
546                                         cb.Append (digitLowerTable [exponent / 100 % 10]);
547                                         cb.Append (digitLowerTable [exponent / 10 % 10]);
548                                         cb.Append (digitLowerTable [exponent % 10]);
549                                 }
550                         }
551
552                         return cb.ToString ();
553                 }
554                 internal static string FormatNumber (NumberStore ns, int precision, NumberFormatInfo nfi)
555                 {
556                         precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
557                         StringBuilder sb = new StringBuilder(ns.IntegerDigits * 3 + precision);
558
559                         ns.RoundDecimal (precision);
560                         bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
561
562                         if (needNegativeSign) {
563                                 switch (nfi.NumberNegativePattern) {
564                                 case 0:
565                                         sb.Append ('(');
566                                         break;
567                                 case 1:
568                                         sb.Append (nfi.NegativeSign);
569                                         break;
570                                 case 2:
571                                         sb.Append (nfi.NegativeSign);
572                                         sb.Append (' ');
573                                         break;
574                                 }
575                         }
576
577                         ns.AppendIntegerStringWithGroupSeparator (sb, nfi.NumberGroupSizes, nfi.NumberGroupSeparator);
578
579                         if (precision > 0) {
580                                 sb.Append (nfi.NumberDecimalSeparator);
581                                 ns.AppendDecimalString (precision, sb);
582                         }
583
584                         if (needNegativeSign) {
585                                 switch (nfi.NumberNegativePattern) {
586                                 case 0:
587                                         sb.Append (')');
588                                         break;
589                                 case 3:
590                                         sb.Append (nfi.NegativeSign);
591                                         break;
592                                 case 4:
593                                         sb.Append (' ');
594                                         sb.Append (nfi.NegativeSign);
595                                         break;
596                                 }
597                         }
598
599                         return sb.ToString ();
600                 }
601                 internal static string FormatPercent (NumberStore ns, int precision, NumberFormatInfo nfi)
602                 {
603                         precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
604                         ns.Multiply10 (2);
605                         ns.RoundDecimal (precision);
606                         bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
607
608                         StringBuilder sb = new StringBuilder(ns.IntegerDigits * 2 + precision + 16);
609
610                         if (!needNegativeSign) {
611                                 if (nfi.PercentPositivePattern == 2) {
612                                         sb.Append (nfi.PercentSymbol);
613                                 }
614                         } else {
615                                 switch (nfi.PercentNegativePattern) {
616                                 case 0:
617                                         sb.Append (nfi.NegativeSign);
618                                         break;
619                                 case 1:
620                                         sb.Append (nfi.NegativeSign);
621                                         break;
622                                 case 2:
623                                         sb.Append (nfi.NegativeSign);
624                                         sb.Append (nfi.PercentSymbol);
625                                         break;
626                                 }
627                         }
628
629                         ns.AppendIntegerStringWithGroupSeparator (sb, nfi.PercentGroupSizes, nfi.PercentGroupSeparator);
630                         
631                         if (precision > 0) {
632                                 sb.Append (nfi.PercentDecimalSeparator);
633                                 ns.AppendDecimalString (precision, sb);
634                         }
635
636                         if (!needNegativeSign) {
637                                 switch (nfi.PercentPositivePattern) {
638                                 case 0:
639                                         sb.Append (' ');
640                                         sb.Append (nfi.PercentSymbol);
641                                         break;
642                                 case 1:
643                                         sb.Append (nfi.PercentSymbol);
644                                         break;
645                                 }
646                         } else {
647                                 switch (nfi.PercentNegativePattern) {
648                                 case 0:
649                                         sb.Append (' ');
650                                         sb.Append (nfi.PercentSymbol);
651                                         break;
652                                 case 1:
653                                         sb.Append (nfi.PercentSymbol);
654                                         break;
655                                 }
656                         }
657
658                         return sb.ToString ();
659                 }
660                 unsafe static string FormatHexadecimal (ulong value, bool positive, int byteSize, int precision, bool upper)
661                 {
662                         if (!positive) {
663                                 /* for large values the cast to ulong is going to return 0 anyway (at least on x86, possibly a MS/Mono runtime bug) */
664 #if FALSE
665                                 if (byteSize < 8) {
666                                         value = (ulong)(Math.Pow (2, byteSize * 8)) - value;
667                                 } else {
668                                         value = 0 - value;
669                                 }
670 #else
671                                 switch (byteSize) {
672                                 case 1:
673                                         value = (ulong)(256UL - value);
674                                         break;
675                                 case 2:
676                                         value = (ulong)(65536UL - value);
677                                         break;
678                                 case 4:
679                                         value = (ulong)(4294967296UL - value);
680                                         break;
681                                 case 8:
682                                         value = 0 - value;
683                                         break;
684                                 }
685 #endif
686                         }
687
688                         char[] digits = (upper ? digitUpperTable : digitLowerTable);
689                         int size = precision > 16 ? precision : 16;
690                         char* buffer = stackalloc char [size];
691                         char* last = buffer + size;
692                         char* ptr = last;
693                         
694                         while (value > 0) {
695                                 *--ptr = digits[value & 0xF];
696                                 value >>= 4;
697                         }
698
699                         while (ptr == last || last - ptr < precision)
700                                 *--ptr = '0';
701
702                         return new string (ptr, 0, (int)(last - ptr));
703                 }
704                 internal static string FormatExponential (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
705                 {
706                         if (precision < 0)
707                                 precision = 6;
708
709                         if (ns.ZeroOnly) {
710                                 StringBuilder sb = new StringBuilder (precision + nfi.PositiveSign.Length + 6);
711                                 sb.Append ('0');
712                                 if (precision > 0) {
713                                         sb.Append ('.');
714                                         sb.Append ('0', precision);
715                                 }
716
717                                 if (upper)
718                                         sb.Append ('E');
719                                 else
720                                         sb.Append ('e');
721
722                                 sb.Append (nfi.PositiveSign);
723                                 sb.Append ('0', 3);
724                                 
725                                 return sb.ToString ();
726                         }
727
728                         int exponent = 0;
729                         while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
730                                 if (ns.DecimalPointPosition > 1) {
731                                         ns.Divide10 (1);
732                                         exponent ++;
733                                 } else {
734                                         ns.Multiply10 (1);
735                                         exponent --;
736                                 }
737                         }
738
739                         if (ns.RoundDecimal (precision)) {
740                                 ns.Divide10 (1);
741                                 exponent ++;
742                         }
743
744                         StringBuilder cb = new StringBuilder (ns.DecimalDigits + 1 + 8);
745
746                         if (!ns.Positive) {
747                                 cb.Append (nfi.NegativeSign);
748                         }
749
750                         ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
751
752                         if (precision > 0) {
753                                 cb.Append (nfi.NumberDecimalSeparator);
754                                 ns.AppendDecimalString (precision, cb);
755                         }
756
757                         if (upper)
758                                 cb.Append ('E');
759                         else
760                                 cb.Append ('e');
761
762                         if (exponent >= 0)
763                                 cb.Append (nfi.PositiveSign);
764                         else {
765                                 cb.Append (nfi.NegativeSign);
766                                 exponent = -exponent;
767                         }
768
769                         if (exponent == 0) {
770                                 cb.Append ('0', 3);
771                         } else if (exponent < 10) {
772                                 cb.Append ('0', 2);
773                                 cb.Append (digitLowerTable [exponent]);
774                         } else if (exponent < 100) {
775                                 cb.Append ('0', 1);
776                                 cb.Append (digitLowerTable [exponent / 10 % 10]);
777                                 cb.Append (digitLowerTable [exponent % 10]);
778                         } else if (exponent < 1000) {
779                                 cb.Append (digitLowerTable [exponent / 100 % 10]);
780                                 cb.Append (digitLowerTable [exponent / 10 % 10]);
781                                 cb.Append (digitLowerTable [exponent % 10]);
782                         /*} else { // exponent range is 0...+-324
783                                 int pos = cb.Length;
784                                 int count = 3;
785                                 while (exponent > 0 || --count > 0) {
786                                         cb.Insert (pos, digitLowerTable [exponent % 10]);
787                                         exponent /= 10;
788                                 }*/
789                         }
790
791                         return cb.ToString ();
792                 }
793                 #endregion
794
795                 #region Custom
796                 internal static string FormatCustom (string format, NumberStore ns, NumberFormatInfo nfi)
797                 {
798                         bool p = ns.Positive;
799                         int offset = 0;
800                         int length = 0;
801                         CustomInfo.GetActiveSection (format,ref p, ns.ZeroOnly, ref offset, ref length);
802                         if (length == 0) {
803                                 return ns.Positive ? String.Empty : nfi.NegativeSign;
804                         }
805                         ns.Positive = p;
806
807                         CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
808 #if false
809                         Console.WriteLine("Format : {0}",format);
810                         Console.WriteLine("DecimalDigits : {0}",info.DecimalDigits);
811                         Console.WriteLine("DecimalPointPos : {0}",info.DecimalPointPos);
812                         Console.WriteLine("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
813                         Console.WriteLine("IntegerDigits : {0}",info.IntegerDigits);
814                         Console.WriteLine("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
815                         Console.WriteLine("IntegerHeadPos : {0}",info.IntegerHeadPos);
816                         Console.WriteLine("UseExponent : {0}",info.UseExponent);
817                         Console.WriteLine("ExponentDigits : {0}",info.ExponentDigits);
818                         Console.WriteLine("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
819                         Console.WriteLine("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
820                         Console.WriteLine("DividePlaces : {0}",info.DividePlaces);
821                         Console.WriteLine("Percents : {0}",info.Percents);
822                         Console.WriteLine("Permilles : {0}",info.Permilles);
823 #endif
824                         StringBuilder sb_int = new StringBuilder(info.IntegerDigits * 2);
825                         StringBuilder sb_dec = new StringBuilder(info.DecimalDigits * 2);
826                         StringBuilder sb_exp = (info.UseExponent ? new StringBuilder(info.ExponentDigits * 2) : null);
827
828                         int diff = 0;
829                         if (info.Percents > 0) {
830                                 ns.Multiply10 (2 * info.Percents);
831                         }
832                         if (info.Permilles > 0) {
833                                 ns.Multiply10 (3 * info.Permilles);
834                         }
835                         if (info.DividePlaces > 0) {
836                                 ns.Divide10 (info.DividePlaces);
837                         }
838
839                         bool expPositive = true;
840                         if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
841                                 if (!ns.ZeroOnly) {
842                                         while (true) {
843                                                 while (ns.IntegerDigits > info.IntegerDigits) {
844                                                         ns.Divide10 (1);
845                                                         diff--;
846                                                         if (ns.IntegerDigits == 1 && ns.GetChar (0) == '0')
847                                                                 break;
848                                                 }
849                                                 while (ns.IntegerDigits < info.IntegerDigits || (ns.IntegerDigits == info.IntegerDigits && ns.GetChar (0) == '0')) {
850                                                         ns.Multiply10 (1);
851                                                         diff++;
852                                                 }
853
854                                                 if (!ns.RoundDecimal (info.DecimalDigits))
855                                                         break;
856                                         }
857                                 }
858
859                                 expPositive = diff <= 0;
860                                 NumberStore.AppendIntegerStringFromUInt32 (sb_exp, (uint)(diff >= 0 ? diff : -diff));
861                         } else {
862                                 ns.RoundDecimal (info.DecimalDigits);
863                                 if (ns.ZeroOnly)
864                                         ns.Positive = true;
865                         }
866
867                         if (info.IntegerDigits != 0 || !ns.CheckZeroOnlyInteger ()) {
868                                 ns.AppendIntegerString (ns.IntegerDigits, sb_int);
869                         }
870                         /* if (sb_int.Length > info.IntegerDigits) {
871                                 int len = 0;
872                                 while (sb_int.Length > info.IntegerDigits && len < sb_int.Length) {
873                                         if (sb_int [len] == '0')
874                                                 len ++;
875                                         else
876                                                 break;
877                                 }
878                                 sb_int.Remove (0, len);
879                         } */
880
881                         ns.AppendDecimalString (ns.DecimalDigits, sb_dec);
882
883                         if (info.UseExponent) {
884                                 if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
885                                         ns.Positive = true;
886
887                                 if (sb_int.Length < info.IntegerDigits)
888                                         sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
889
890                                 while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
891                                         sb_exp.Insert (0, '0');
892
893                                 if (expPositive && !info.ExponentNegativeSignOnly)
894                                         sb_exp.Insert (0, nfi.PositiveSign);
895                                 else if(!expPositive)
896                                         sb_exp.Insert (0, nfi.NegativeSign);
897                         } else {
898                                 if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
899                                         sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
900                                 if (info.IntegerDigits == info.IntegerHeadSharpDigits && NumberStore.IsZeroOnly (sb_int))
901                                         sb_int.Remove (0, sb_int.Length);
902                         }
903
904                         ZeroTrimEnd (sb_dec, true);
905                         while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
906                                 sb_dec.Append ('0');
907                         if (sb_dec.Length > info.DecimalDigits)
908                                 sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
909
910                         return info.Format (format, offset, length, nfi, ns.Positive, sb_int, sb_dec, sb_exp);
911                 }
912
913                 private class CustomInfo
914                 {
915                         public bool UseGroup = false;
916                         public int DecimalDigits = 0;
917                         public int DecimalPointPos = -1;
918                         public int DecimalTailSharpDigits = 0;
919                         public int IntegerDigits = 0;
920                         public int IntegerHeadSharpDigits = 0;
921                         public int IntegerHeadPos = 0;
922                         public bool UseExponent = false;
923                         public int ExponentDigits = 0;
924                         public int ExponentTailSharpDigits = 0;
925                         public bool ExponentNegativeSignOnly = true;
926                         public int DividePlaces = 0;
927                         public int Percents = 0;
928                         public int Permilles = 0;
929
930                         public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
931                         {
932                                 int[] lens = new int [3];
933                                 int index = 0;
934                                 int lastPos = 0;
935                                 char literal = '\0';
936                                 for (int i = 0; i < format.Length; i++) {
937                                         char c = format [i];
938
939                                         if (c == literal || (literal == '\0' && (c == '\"' || c == '\''))) {
940                                                 if (literal == '\0')
941                                                         literal = c;
942                                                 else
943                                                         literal = '\0';
944                                                 continue;
945                                         }
946                                         
947                                         if (literal == '\0' && format [i] == ';' && (i == 0 || format [i - 1] != '\\')) {
948                                                 lens [index ++] = i - lastPos;
949                                                 lastPos = i + 1;
950                                                 if (index == 3)
951                                                         break;
952                                         }
953                                 }
954
955                                 if (index == 0) {
956                                         offset = 0;
957                                         length = format.Length;
958                                         return;
959                                 }
960                                 if (index == 1) {
961                                         if (positive || zero) {
962                                                 offset = 0;
963                                                 length = lens [0];
964                                                 return;
965                                         }
966                                         if (lens [0] + 1 < format.Length) {
967                                                 positive = true;
968                                                 offset = lens [0] + 1;
969                                                 length = format.Length - offset;
970                                                 return;
971                                         } else {
972                                                 offset = 0;
973                                                 length = lens [0];
974                                                 return;
975                                         }
976                                 }
977                                 if (index == 2) {
978                                         if (zero) {
979                                                 offset = lens [0] + lens [1] + 2;
980                                                 length = format.Length - offset;
981                                                 return;
982                                         }
983                                         if (positive) {
984                                                 offset = 0;
985                                                 length = lens [0];
986                                                 return;
987                                         }
988                                         if (lens [1] > 0) {
989                                                 positive = true;
990                                                 offset = lens [0] + 1;
991                                                 length = lens [1];
992                                                 return;
993                                         } else {
994                                                 offset = 0;
995                                                 length = lens [0];
996                                                 return;
997                                         }
998                                 }
999                                 if (index == 3) {
1000                                         if (zero) {
1001                                                 offset = lens [0] + lens [1] + 2;
1002                                                 length = lens [2];
1003                                                 return;
1004                                         }
1005                                         if (positive) {
1006                                                 offset = 0;
1007                                                 length = lens [0];
1008                                                 return;
1009                                         }
1010                                         if (lens [1] > 0) {
1011                                                 positive = true;
1012                                                 offset = lens [0] + 1;
1013                                                 length = lens [1];
1014                                                 return;
1015                                         } else {
1016                                                 offset = 0;
1017                                                 length = lens [0];
1018                                                 return;
1019                                         }
1020                                 }
1021
1022                                 throw new ArgumentException ();
1023                         }
1024
1025                         public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
1026                         {
1027                                 char literal = '\0';
1028                                 bool integerArea = true;
1029                                 bool decimalArea = false;
1030                                 bool exponentArea = false;
1031                                 bool sharpContinues = true;
1032
1033                                 CustomInfo info = new CustomInfo ();
1034                                 int groupSeparatorCounter = 0;
1035
1036                                 for (int i = offset; i - offset < length; i++) {
1037                                         char c = format [i];
1038
1039                                         if (c == literal && c != '\0') {
1040                                                 literal = '\0';
1041                                                 continue;
1042                                         }
1043                                         if (literal != '\0')
1044                                                 continue;
1045
1046                                         if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
1047                                                 exponentArea = false;
1048                                                 integerArea = (info.DecimalPointPos < 0);
1049                                                 decimalArea = !integerArea;
1050                                                 i--;
1051                                                 continue;
1052                                         }
1053
1054                                         switch (c) {
1055                                         case '\\':
1056                                                 i ++;
1057                                                 continue;
1058                                         case '\'':
1059                                         case '\"':
1060                                                 if (c == '\"' || c == '\'') {
1061                                                         literal = c;
1062                                                 }
1063                                                 continue;
1064                                         case '#':
1065                                                 if (sharpContinues && integerArea)
1066                                                         info.IntegerHeadSharpDigits ++;
1067                                                 else if (decimalArea)
1068                                                         info.DecimalTailSharpDigits ++;
1069                                                 else if (exponentArea)
1070                                                         info.ExponentTailSharpDigits ++;
1071
1072                                                 goto case '0';
1073                                         case '0':
1074                                                 if (c != '#') {
1075                                                         sharpContinues = false;
1076                                                         if (decimalArea)
1077                                                                 info.DecimalTailSharpDigits = 0;
1078                                                         else if (exponentArea)
1079                                                                 info.ExponentTailSharpDigits = 0;
1080                                                 }
1081                                                 if (info.IntegerHeadPos == -1)
1082                                                         info.IntegerHeadPos = i;
1083
1084                                                 if (integerArea) {
1085                                                         info.IntegerDigits ++;
1086                                                         if (groupSeparatorCounter > 0)
1087                                                                 info.UseGroup = true;
1088                                                         groupSeparatorCounter = 0;
1089                                                 } else if (decimalArea) {
1090                                                         info.DecimalDigits ++;
1091                                                 } else if (exponentArea) {
1092                                                         info.ExponentDigits ++;
1093                                                 }
1094                                                 break;
1095                                         case 'e':
1096                                         case 'E':
1097                                                 if (info.UseExponent)
1098                                                         break;
1099
1100                                                 info.UseExponent = true;
1101                                                 integerArea = false;
1102                                                 decimalArea = false;
1103                                                 exponentArea = true;
1104                                                 if (i + 1 - offset < length) {
1105                                                         char nc = format [i + 1];
1106                                                         if (nc == '+')
1107                                                                 info.ExponentNegativeSignOnly = false;
1108                                                         if (nc == '+' || nc == '-') {
1109                                                                 i ++;
1110                                                         } else if (nc != '0' && nc != '#') {
1111                                                                 info.UseExponent = false;
1112                                                                 if (info.DecimalPointPos < 0)
1113                                                                         integerArea = true;
1114                                                         }
1115                                                         c = '\0';
1116                                                 }
1117                                                 
1118                                                 break;
1119                                         case '.':
1120                                                 integerArea = false;
1121                                                 decimalArea = true;
1122                                                 exponentArea = false;
1123                                                 if (info.DecimalPointPos == -1)
1124                                                         info.DecimalPointPos = i;
1125                                                 break;
1126                                         case '%':
1127                                                 info.Percents++;
1128                                                 break;
1129                                         case '\u2030':
1130                                                 info.Permilles++;
1131                                                 break;
1132                                         case ',':
1133                                                 if (integerArea && info.IntegerDigits > 0)
1134                                                         groupSeparatorCounter ++;
1135                                                 break;
1136                                         default:
1137                                                 break;
1138                                         }
1139                                 }
1140
1141                                 if (info.ExponentDigits == 0)
1142                                         info.UseExponent = false;
1143                                 else
1144                                         info.IntegerHeadSharpDigits = 0;
1145
1146                                 if (info.DecimalDigits == 0)
1147                                         info.DecimalPointPos = -1;
1148
1149                                 info.DividePlaces += groupSeparatorCounter * 3;
1150
1151                                 return info;
1152                         }
1153
1154                         public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
1155                         {
1156                                 StringBuilder sb = new StringBuilder ();
1157                                 char literal = '\0';
1158                                 bool integerArea = true;
1159                                 bool decimalArea = false;
1160                                 int  intSharpCounter = 0;
1161                                 int sb_int_index = 0;
1162                                 int sb_dec_index = 0;
1163
1164                                 int[] groups = nfi.NumberGroupSizes;
1165                                 string groupSeparator = nfi.NumberGroupSeparator;
1166                                 int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0, fraction = 0;
1167                                 if (UseGroup && groups.Length > 0) {
1168                                         intLen = sb_int.Length;
1169                                         for (int i = 0; i < groups.Length; i++) {
1170                                                 total += groups [i];
1171                                                 if (total <= intLen)
1172                                                         groupIndex = i;
1173                                         }
1174                                         groupSize = groups [groupIndex];
1175                                         fraction = intLen > total ? intLen - total : 0;
1176                                         if (groupSize == 0) {
1177                                                 while (groupIndex >= 0 && groups [groupIndex] == 0)
1178                                                         groupIndex --;
1179                                                 
1180                                                 groupSize = fraction > 0 ? fraction : groups [groupIndex];
1181                                         }
1182                                         if (fraction == 0) {
1183                                                 counter = groupSize;
1184                                         } else {
1185                                                 groupIndex += fraction / groupSize;
1186                                                 counter = fraction % groupSize;
1187                                                 if (counter == 0)
1188                                                         counter = groupSize;
1189                                                 else
1190                                                         groupIndex ++;
1191                                         }
1192                                 } else {
1193                                         UseGroup = false;
1194                                 }
1195
1196                                 for (int i = offset; i - offset < length; i++) {
1197                                         char c = format [i];
1198
1199                                         if (c == literal && c != '\0') {
1200                                                 literal = '\0';
1201                                                 continue;
1202                                         }
1203                                         if (literal != '\0') {
1204                                                 sb.Append (c);
1205                                                 continue;
1206                                         }
1207
1208                                         switch (c) {
1209                                         case '\\':
1210                                                 i ++;
1211                                                 if (i - offset < length)
1212                                                         sb.Append (format [i]);
1213                                                 continue;
1214                                         case '\'':
1215                                         case '\"':
1216                                                 if (c == '\"' || c == '\'') {
1217                                                         literal = c;
1218                                                 }
1219                                                 continue;
1220                                         case '#':
1221                                                 goto case '0';
1222                                         case '0':
1223                                                 if (integerArea) {
1224                                                         intSharpCounter++;
1225                                                         if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
1226                                                                 while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
1227                                                                         sb.Append (sb_int[ sb_int_index++]);
1228                                                                         if (UseGroup && --intLen > 0 && --counter == 0) {
1229                                                                                 sb.Append (groupSeparator);
1230                                                                                 if (--groupIndex < groups.Length && groupIndex >= 0)
1231                                                                                         groupSize = groups [groupIndex];
1232                                                                                 counter = groupSize;
1233                                                                         }
1234                                                                 }
1235                                                         break;
1236                                                 } else if (decimalArea) {
1237                                                         if (sb_dec_index < sb_dec.Length)
1238                                                                 sb.Append (sb_dec [sb_dec_index++]);
1239                                                         break;
1240                                                 }
1241
1242                                                 sb.Append (c);
1243                                                 break;
1244                                         case 'e':
1245                                         case 'E':
1246                                                 if (sb_exp == null || !UseExponent) {
1247                                                         sb.Append (c);
1248                                                         break;
1249                                                 }
1250
1251                                                 bool flag1 = true;
1252                                                 bool flag2 = false;
1253                                                 
1254                                                 int q;
1255                                                 for (q = i + 1; q - offset < length; q++) {
1256                                                         if (format [q] == '0') {
1257                                                                 flag2 = true;
1258                                                                 continue;
1259                                                         }
1260                                                         if (q == i + 1 && (format [q] == '+' || format [q] == '-')) {
1261                                                                 continue;
1262                                                         }
1263                                                         if (!flag2)
1264                                                                 flag1 = false;
1265                                                         break;
1266                                                 }
1267
1268                                                 if (flag1) {
1269                                                         i = q - 1;
1270                                                         integerArea = (DecimalPointPos < 0);
1271                                                         decimalArea = !integerArea;
1272
1273                                                         sb.Append (c);
1274                                                         sb.Append (sb_exp);
1275                                                         sb_exp = null;
1276                                                 } else
1277                                                         sb.Append (c);
1278
1279                                                 break;
1280                                         case '.':
1281                                                 if (DecimalPointPos == i) {
1282                                                         if (DecimalDigits > 0) {
1283                                                                 while (sb_int_index < sb_int.Length)
1284                                                                         sb.Append (sb_int [sb_int_index++]);
1285                                                         }
1286                                                         if (sb_dec.Length > 0)
1287                                                                 sb.Append (nfi.NumberDecimalSeparator);
1288                                                 }
1289                                                 integerArea = false;
1290                                                 decimalArea = true;
1291                                                 break;
1292                                         case ',':
1293                                                 break;
1294                                         case '%':
1295                                                 sb.Append (nfi.PercentSymbol);
1296                                                 break;
1297                                         case '\u2030':
1298                                                 sb.Append (nfi.PerMilleSymbol);
1299                                                 break;
1300                                         default:
1301                                                 sb.Append (c);
1302                                                 break;
1303                                         }
1304                                 }
1305
1306                                 if (!positive)
1307                                         sb.Insert (0, nfi.NegativeSign);
1308
1309                                 return sb.ToString ();
1310                         }
1311                 }
1312
1313                 #endregion
1314
1315                 #region Internal structures
1316                 internal struct NumberStore
1317                 {
1318                         bool _NaN;
1319                         bool _infinity;
1320                         bool _positive;
1321                         int  _decPointPos;
1322                         int  _defPrecision;
1323                         int  _defMaxPrecision;
1324                         int  _defByteSize;
1325
1326                         byte[] _digits;
1327
1328                         static uint [] IntList = new uint [] {
1329                                 1,
1330                                 10,
1331                                 100,
1332                                 1000,
1333                                 10000,
1334                                 100000,
1335                                 1000000,
1336                                 10000000,
1337                                 100000000,
1338                                 1000000000,
1339                         };
1340
1341                         static ulong [] ULongList = new ulong [] {
1342                                 1,
1343                                 10,
1344                                 100,
1345                                 1000,
1346                                 10000,
1347                                 100000,
1348                                 1000000,
1349                                 10000000,
1350                                 100000000,
1351                                 1000000000,
1352                                 10000000000,
1353                                 100000000000,
1354                                 1000000000000,
1355                                 10000000000000,
1356                                 100000000000000,
1357                                 1000000000000000,
1358                                 10000000000000000,
1359                                 100000000000000000,
1360                                 1000000000000000000,
1361                                 10000000000000000000,
1362                         };
1363
1364                         #region Constructors
1365                         public NumberStore (long value)
1366                         {
1367                                 _infinity = _NaN = false;
1368                                 _defByteSize = 8;
1369                                 _defMaxPrecision = _defPrecision = 19;
1370                                 _positive = value >= 0;
1371
1372                                 if (value == 0) {
1373                                         _digits = new byte []{0};
1374                                         _decPointPos = 1;
1375                                         return;
1376                                 }
1377                                 
1378                                 ulong v = (ulong)(_positive ? value : -value);
1379
1380                                 int i = 18, j = 0;
1381
1382                                 if (v < 10)
1383                                         i = 0;
1384                                 else if (v < 100)
1385                                         i = 1;
1386                                 else if (v < 1000)
1387                                         i = 2;
1388                                 else if (v < 10000)
1389                                         i = 3;
1390                                 else if (v < 100000)
1391                                         i = 4;
1392                                 else if (v < 1000000)
1393                                         i = 5;
1394                                 else if (v < 10000000)
1395                                         i = 6;
1396                                 else if (v < 100000000)
1397                                         i = 7;
1398                                 else if (v < 1000000000)
1399                                         i = 8;
1400                                 else if (v < 10000000000)
1401                                         i = 9;
1402                                 else if (v < 100000000000)
1403                                         i = 10;
1404                                 else if (v < 1000000000000)
1405                                         i = 11;
1406                                 else if (v < 10000000000000)
1407                                         i = 12;
1408                                 else if (v < 100000000000000)
1409                                         i = 13;
1410                                 else if (v < 1000000000000000)
1411                                         i = 14;
1412                                 else if (v < 10000000000000000)
1413                                         i = 15;
1414                                 else if (v < 100000000000000000)
1415                                         i = 16;
1416                                 else if (v < 1000000000000000000)
1417                                         i = 17;
1418                                 else
1419                                         i = 18;
1420
1421                                 _digits = new byte [i + 1];
1422                                 do {
1423                                         ulong n = v / ULongList [i];
1424                                         _digits [j++] = (byte)n;
1425                                         v -= ULongList [i--] * n;
1426                                 } while (i >= 0);
1427
1428                                 _decPointPos = _digits.Length;
1429                         }
1430                         public NumberStore (int value)
1431                         {
1432                                 _infinity = _NaN = false;
1433                                 _defByteSize = 4;
1434                                 _defMaxPrecision = _defPrecision = 10;
1435                                 _positive = value >= 0;
1436
1437                                 if (value == 0) {
1438                                         _digits = new byte []{0};
1439                                         _decPointPos = 1;
1440                                         return;
1441                                 }
1442                                 
1443                                 uint v = (uint)(_positive ? value : -value);
1444
1445                                 int i = 9, j = 0;
1446
1447                                 if (v < 10)
1448                                         i = 0;
1449                                 else if (v < 100)
1450                                         i = 1;
1451                                 else if (v < 1000)
1452                                         i = 2;
1453                                 else if (v < 10000)
1454                                         i = 3;
1455                                 else if (v < 100000)
1456                                         i = 4;
1457                                 else if (v < 1000000)
1458                                         i = 5;
1459                                 else if (v < 10000000)
1460                                         i = 6;
1461                                 else if (v < 100000000)
1462                                         i = 7;
1463                                 else if (v < 1000000000)
1464                                         i = 8;
1465                                 else
1466                                         i = 9;
1467
1468                                 _digits = new byte [i + 1];
1469                                 do {
1470                                         uint n = v / IntList [i];
1471                                         _digits [j++] = (byte)n;
1472                                         v -= IntList [i--] * n;
1473                                 } while (i >= 0);
1474
1475                                 _decPointPos = _digits.Length;
1476                         }
1477                         public NumberStore (short value) : this ((int)value)
1478                         {
1479                                 _defByteSize = 2;
1480                                 _defMaxPrecision = _defPrecision = 5;
1481                         }
1482                         public NumberStore (sbyte value) : this ((int)value)
1483                         {
1484                                 _defByteSize = 1;
1485                                 _defMaxPrecision = _defPrecision = 3;
1486                         }
1487
1488                         public NumberStore (ulong value)
1489                         {
1490                                 _infinity = _NaN = false;
1491                                 _defByteSize = 8;
1492                                 _defMaxPrecision = _defPrecision = 20;
1493                                 _positive = true;
1494
1495                                 if (value == 0) {
1496                                         _digits = new byte []{0};
1497                                         _decPointPos = 1;
1498                                         return;
1499                                 }
1500
1501                                 int i = 19, j = 0;
1502
1503                                 if (value < 10)
1504                                         i = 0;
1505                                 else if (value < 100)
1506                                         i = 1;
1507                                 else if (value < 1000)
1508                                         i = 2;
1509                                 else if (value < 10000)
1510                                         i = 3;
1511                                 else if (value < 100000)
1512                                         i = 4;
1513                                 else if (value < 1000000)
1514                                         i = 5;
1515                                 else if (value < 10000000)
1516                                         i = 6;
1517                                 else if (value < 100000000)
1518                                         i = 7;
1519                                 else if (value < 1000000000)
1520                                         i = 8;
1521                                 else if (value < 10000000000)
1522                                         i = 9;
1523                                 else if (value < 100000000000)
1524                                         i = 10;
1525                                 else if (value < 1000000000000)
1526                                         i = 11;
1527                                 else if (value < 10000000000000)
1528                                         i = 12;
1529                                 else if (value < 100000000000000)
1530                                         i = 13;
1531                                 else if (value < 1000000000000000)
1532                                         i = 14;
1533                                 else if (value < 10000000000000000)
1534                                         i = 15;
1535                                 else if (value < 100000000000000000)
1536                                         i = 16;
1537                                 else if (value < 1000000000000000000)
1538                                         i = 17;
1539                                 else if (value < 10000000000000000000)
1540                                         i = 18;
1541                                 else
1542                                         i = 19;
1543
1544                                 _digits = new byte [i + 1];
1545                                 do {
1546                                         ulong n = value / ULongList [i];
1547                                         _digits [j++] = (byte)n;
1548                                         value -= ULongList [i--] * n;
1549                                 } while (i >= 0);
1550
1551                                 _decPointPos = _digits.Length;
1552                         }
1553                         public NumberStore (uint value)
1554                         {
1555                                 _infinity = _NaN = false;
1556                                 _positive = true;
1557                                 _defByteSize = 4;
1558                                 _defMaxPrecision = _defPrecision = 10;
1559
1560                                 if (value == 0) {
1561                                         _digits = new byte []{0};
1562                                         _decPointPos = 1;
1563                                         return;
1564                                 }
1565                                 
1566                                 int i = 9, j = 0;
1567
1568                                 if (value < 10)
1569                                         i = 0;
1570                                 else if (value < 100)
1571                                         i = 1;
1572                                 else if (value < 1000)
1573                                         i = 2;
1574                                 else if (value < 10000)
1575                                         i = 3;
1576                                 else if (value < 100000)
1577                                         i = 4;
1578                                 else if (value < 1000000)
1579                                         i = 5;
1580                                 else if (value < 10000000)
1581                                         i = 6;
1582                                 else if (value < 100000000)
1583                                         i = 7;
1584                                 else if (value < 1000000000)
1585                                         i = 8;
1586                                 else
1587                                         i = 9;
1588
1589                                 _digits = new byte [i + 1];
1590                                 do {
1591                                         uint n = value / IntList [i];
1592                                         _digits [j++] = (byte)n;
1593                                         value -= IntList [i--] * n;
1594                                 } while (i >= 0);
1595
1596                                 _decPointPos = _digits.Length;
1597                         }
1598                         public NumberStore (ushort value) : this ((uint)value)
1599                         {
1600                                 _defByteSize = 2;
1601                                 _defMaxPrecision = _defPrecision = 5;
1602                         }
1603                         public NumberStore (byte value) : this ((uint)value)
1604                         {
1605                                 _defByteSize = 1;
1606                                 _defMaxPrecision = _defPrecision = 3;
1607                         }
1608
1609                         public NumberStore(double value)
1610                         {
1611                                 _digits = null;
1612                                 _defByteSize = 64;
1613                                 _defPrecision = 15;
1614                                 _defMaxPrecision = _defPrecision + 2;
1615
1616                                 if (double.IsNaN (value) || double.IsInfinity (value)) {
1617                                         _NaN = double.IsNaN (value);
1618                                         _infinity = double.IsInfinity (value);
1619                                         _positive = value > 0;
1620                                         _decPointPos = 0;
1621                                         return;
1622                                 } else {
1623                                         _NaN = _infinity = false;
1624                                 }
1625
1626                                 long bits = BitConverter.DoubleToInt64Bits (value);
1627                                 _positive = (bits >= 0);
1628                                 int e = (int) ((bits >> 52) & 0x7ffL);
1629                                 long m = bits & 0xfffffffffffffL;
1630
1631                                 if (e == 0 && m == 0) {
1632                                         _decPointPos = 1;
1633                                         _digits = new byte []{0};
1634                                         _positive = true;
1635                                         return;
1636                                 }
1637
1638                                 if (e == 0) {
1639                                         e ++;
1640                                 } else if (e != 0) {
1641                                         m |= (1L << 52);
1642                                 }
1643
1644                                 e -= 1075;
1645
1646                                 int nsize = 0;
1647                                 while ((m & 1) == 0) {
1648                                         m >>= 1;
1649                                         e ++;
1650                                         nsize ++;
1651                                 }
1652
1653                                 long mt = m;
1654                                 int length = 1;
1655                                 byte[] temp = new byte [56];
1656                                 for (int i = temp.Length - 1; i >= 0; i--, length++) {
1657                                         temp [i] = (byte)(mt % 10);
1658                                         mt /= 10;
1659                                         if (mt == 0)
1660                                                 break;
1661                                 }
1662
1663                                 _decPointPos = temp.Length - 1;
1664
1665                                 if (e >= 0) {
1666                                         for (int i = 0; i < e; i++) {
1667                                                 if (MultiplyBy (ref temp, ref length, 2)) {
1668                                                         _decPointPos ++;
1669                                                 }
1670                                         }
1671                                 } else {
1672                                         for (int i = 0; i < -e; i++) {
1673                                                 if (MultiplyBy (ref temp, ref length, 5)) {
1674                                                         _decPointPos ++;
1675                                                 }
1676                                         }
1677                                         _decPointPos += e;
1678                                 }
1679
1680                                 int ulvc = 1;
1681                                 ulong ulv = 0;
1682                                 for (int i = 0; i < temp.Length; i++)
1683                                         if (temp [i] != 0) {
1684                                                 _decPointPos -= i - 1;
1685                                                 _digits = new byte [temp.Length - i];
1686                                                 for (int q = i; q < temp.Length; q++) {
1687                                                         _digits [q - i] = temp [q];
1688                                                         if (ulvc < 20) {
1689                                                                 ulv = ulv * 10 + temp [q];
1690                                                                 ulvc ++;
1691                                                         }
1692                                                 }
1693                                                 break;
1694                                         }
1695
1696                                 RoundEffectiveDigits (17, true, true);
1697                         }
1698                         public NumberStore(float value)
1699                         {
1700                                 _digits = null;
1701                                 _defByteSize = 32;
1702                                 _defPrecision = 7;
1703                                 _defMaxPrecision = _defPrecision + 2;
1704
1705                                 if (float.IsNaN (value) || float.IsInfinity (value)) {
1706                                         _NaN = float.IsNaN (value);
1707                                         _infinity = float.IsInfinity (value);
1708                                         _positive = value > 0;
1709                                         _decPointPos = 0;
1710                                         return;
1711                                 } else
1712                                         _infinity = _NaN = false;
1713
1714                                 long bits = BitConverter.DoubleToInt64Bits (value);
1715                                 _positive = (bits >= 0);
1716                                 int e = (int) ((bits >> 52) & 0x7ffL);
1717                                 long m = bits & 0xfffffffffffffL;
1718
1719                                 if (e == 0 && m == 0) {
1720                                         _decPointPos = 1;
1721                                         _digits = new byte []{0};
1722                                         _positive = true;
1723                                         return;
1724                                 }
1725
1726                                 if (e == 0) {
1727                                         e ++;
1728                                 } else if (e != 0) {
1729                                         m |= (1L << 52);
1730                                 }
1731
1732                                 e -= 1075;
1733
1734                                 int nsize = 0;
1735                                 while ((m & 1) == 0) {
1736                                         m >>= 1;
1737                                         e ++;
1738                                         nsize ++;
1739                                 }
1740
1741                                 long mt = m;
1742                                 int length = 1;
1743                                 byte[] temp = new byte [26];
1744                                 for (int i = temp.Length - 1; i >= 0; i--, length++) {
1745                                         temp [i] = (byte)(mt % 10);
1746                                         mt /= 10;
1747                                         if (mt == 0)
1748                                                 break;
1749                                 }
1750
1751                                 _decPointPos = temp.Length - 1;
1752
1753                                 if (e >= 0) {
1754                                         for (int i = 0; i < e; i++) {
1755                                                 if (MultiplyBy (ref temp, ref length, 2)) {
1756                                                         _decPointPos ++;
1757                                                 }
1758                                         }
1759                                 } else {
1760                                         for (int i = 0; i < -e; i++) {
1761                                                 if (MultiplyBy (ref temp, ref length, 5)) {
1762                                                         _decPointPos ++;
1763                                                 }
1764                                         }
1765                                         _decPointPos += e;
1766                                 }
1767
1768                                 int ulvc = 1;
1769                                 ulong ulv = 0;
1770                                 for (int i = 0; i < temp.Length; i++)
1771                                         if (temp [i] != 0) {
1772                                                 _decPointPos -= i - 1;
1773                                                 _digits = new byte [temp.Length - i];
1774                                                 for (int q = i; q < temp.Length; q++) {
1775                                                         _digits [q - i] = temp [q];
1776                                                         if (ulvc < 20) {
1777                                                                 ulv = ulv * 10 + temp [q];
1778                                                                 ulvc ++;
1779                                                         }
1780                                                 }
1781                                                 break;
1782                                         }
1783
1784                                 RoundEffectiveDigits (9, true, true);
1785                         }
1786
1787                         internal bool MultiplyBy (ref byte[] buffer,ref int length, int amount)
1788                         {
1789                                 int mod = 0;
1790                                 int ret;
1791                                 int start = buffer.Length - length - 1;
1792                                 if (start < 0) start = 0;
1793
1794                                 for (int i = buffer.Length - 1; i > start; i--) {
1795                                         ret = buffer [i] * amount + mod;
1796                                         mod = ret / 10;
1797                                         buffer [i] = (byte)(ret % 10);
1798                                 }
1799
1800                                 if (mod != 0) {
1801                                         length = buffer.Length - start;
1802
1803                                         if (start == 0) {
1804                                                 buffer [0] = (byte)mod;
1805                                                 Array.Copy (buffer, 0, buffer, 1, buffer.Length - 1);
1806                                                 buffer [0] = 0;
1807                                                 return true;
1808                                         }
1809                                         else {
1810                                                 buffer [start] = (byte)mod;
1811                                         }
1812                                 }
1813
1814                                 return false;
1815                         }
1816
1817
1818                         public NumberStore (decimal value)
1819                         {
1820                                 int[] bits = decimal.GetBits (value);
1821                                 _positive = (bits [3] & 0x80000000) == 0;
1822                                 bits[3] = bits [3] & 0x7FFFFFFF;
1823                                 int ss = (bits [3] & 0x1F0000) >> 16;
1824                                 ulong lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
1825                                 ulong hi = (uint)bits [2];
1826                                 uint rest = 0;
1827
1828                                 int digits = 0;
1829                                 while (hi > 0 || lo > 0) {
1830                                         digits ++;
1831                                         DivideDecimal (ref lo, ref hi, 10, ref rest);
1832                                 }
1833
1834                                 lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
1835                                 hi = (uint)bits [2];
1836
1837                                 _digits = new byte [digits];
1838                                 int i = digits;
1839                                 while (hi > 0 || lo > 0) {
1840                                         DivideDecimal (ref lo, ref hi, 10, ref rest);
1841                                         _digits [--i] = (byte)rest;
1842                                 }
1843
1844                                 _infinity = _NaN = false;
1845                                 _decPointPos = _digits.Length - ss;
1846                                 _defPrecision = _defMaxPrecision = 100;
1847                                 _defByteSize = 16;
1848                         }
1849                         static int DivideDecimal (ref ulong lo, ref ulong hi, uint factor, ref uint rest)
1850                         {
1851                                 ulong a, b, c, h;
1852
1853                                 h = hi;
1854                                 a = (uint)(h >> 32);
1855                                 b = a / factor;
1856                                 a -= b * factor;
1857                                 a <<= 32;
1858                                 a |= (uint) h;
1859                                 c = a / factor;
1860                                 a -= c * factor;
1861                                 a <<= 32;
1862                                 hi = b << 32 | (uint)c;
1863
1864                                 h = lo;
1865                                 a |= (uint)(h >> 32);
1866                                 b = a / factor;
1867                                 a -= b * factor;
1868                                 a <<= 32;
1869                                 a |= (uint) h;
1870                                 c = a / factor;
1871                                 a -= c * factor;
1872                                 lo = b << 32 | (uint)c;
1873
1874                                 rest = (uint)a;
1875
1876                                 a <<= 1;
1877                                 return (a >= factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
1878                         }
1879                         #endregion
1880
1881                         #region Public Property
1882                         public bool IsNaN 
1883                         {
1884                                 get { return _NaN; }
1885                         }
1886                         public bool IsInfinity {
1887                                 get { return _infinity; }
1888                         }
1889                         public int DecimalPointPosition {
1890                                 get { return _decPointPos; }
1891                         }
1892                         public bool Positive {
1893                                 get { return _positive; }
1894                                 set { _positive = value;}
1895                         }
1896                         public int DefaultPrecision {
1897                                 get { return _defPrecision; }
1898                         }
1899                         public int DefaultMaxPrecision {
1900                                 get { return _defMaxPrecision; }
1901                         }
1902                         public int DefaultByteSize {
1903                                 get { return _defByteSize; }
1904                         }
1905                         public bool HasDecimal {
1906                                 get { return _digits.Length > _decPointPos; }
1907                         }
1908                         public int IntegerDigits {
1909                                 get { return _decPointPos > 0 ? _decPointPos : 1; }
1910                         }
1911                         public int DecimalDigits {
1912                                 get { return HasDecimal ? _digits.Length - _decPointPos : 0; }
1913                         }
1914                         public bool IsFloatingSource {
1915                                 get { return _defPrecision == 15 || _defPrecision == 7; }
1916                         }
1917                         public bool IsDecimalSource {
1918                                 get { return _defPrecision > 30; }
1919                         }
1920                         public bool IsBankerApplicable {
1921                                 get {
1922                                         if ((_digits == null) || (_digits.Length < 2))
1923                                                 return false;
1924                                         return ((_digits [_digits.Length - 2] & 1) == 1);
1925                                 }
1926                         }
1927                         public bool ZeroOnly {
1928                                 get {
1929                                         for (int i = 0; i < _digits.Length; i++)
1930                                                 if (_digits [i] != 0)
1931                                                         return false;
1932                                         return true;
1933                                 }
1934                         }
1935                         #endregion
1936
1937                         #region Public Method
1938
1939                         #region Round
1940                         public bool RoundPos (int pos)
1941                         {
1942                                 return RoundPos (pos, true);
1943                         }
1944                         public bool RoundPos (int pos, bool carryFive)
1945                         {
1946                                 bool carry = false;
1947
1948                                 if (_decPointPos <= 0)
1949                                         pos = pos - _decPointPos - 1;
1950
1951                                 if (pos >= _digits.Length)
1952                                         return false;
1953
1954                                 if (pos < 0) {
1955                                         _digits = new byte [1];
1956                                         _digits [0] = 0;
1957                                         _decPointPos = 1;
1958                                         _positive = true;
1959                                         return false;
1960                                 }
1961
1962                                 for (int i = pos; i >= 0; i--) {
1963                                         RoundHelper (i, carryFive, ref carry);
1964                                         if (!carry)
1965                                                 break;
1966                                 }
1967
1968                                 if (carry) {
1969                                         byte[] temp = new byte [_digits.Length + 1];
1970                                         _digits.CopyTo (temp, 1);
1971                                         temp [0] = 1;
1972                                         _digits = temp;
1973                                         _decPointPos ++;
1974                                         pos ++;
1975                                 }
1976
1977                                 for (int i = pos; i < _digits.Length; i++)
1978                                         _digits [i] = 0;
1979                                 TrimDecimalEndZeros ();
1980
1981                                 return carry;
1982                         }
1983                         public bool RoundDecimal (int decimals)
1984                         {
1985                                 return RoundDecimal (decimals, true, true);
1986                         }
1987                         public bool RoundDecimal (int decimals, bool carryFive, bool countZero)
1988                         {
1989                                 bool carry = false;
1990
1991                                 if (countZero || (_decPointPos > 0))
1992                                         decimals += _decPointPos;
1993
1994                                 if (!HasDecimal || decimals >= _digits.Length)
1995                                         return false;
1996
1997                                 if (decimals < 0) {
1998                                         _digits = new byte [1];
1999                                         _digits [0] = 0;
2000                                         _decPointPos = 1;
2001                                         _positive = true;
2002                                         return false;
2003                                 }
2004
2005                                 for (int i = decimals; i >= 0; i--) {
2006                                         RoundHelper (i, carryFive, ref carry);
2007                                         if (!carry)
2008                                                 break;
2009                                 }
2010
2011                                 if (carry) {
2012                                         byte[] temp = new byte [_digits.Length + 1];
2013                                         _digits.CopyTo (temp, 1);
2014                                         temp [0] = 1;
2015                                         _digits = temp;
2016                                         _decPointPos ++;
2017                                         decimals ++;
2018                                 }
2019
2020                                 for (int i = decimals; i < _digits.Length; i++)
2021                                         _digits [i] = 0;
2022                                 TrimDecimalEndZeros ();
2023
2024                                 return carry;
2025                         }
2026                         void RoundHelper (int index, bool carryFive, ref bool carry)
2027                         {
2028                                 if (carry) {
2029                                         if (_digits [index] == 9) {
2030                                                 carry = true;
2031                                                 _digits [index] = 0;
2032                                         } else {
2033                                                 carry = false;
2034                                                 _digits [index] ++;
2035                                         }
2036                                 } else if (_digits [index] >= (carryFive ? 5 : 6)) {
2037                                         carry = true;
2038                                 }
2039                         }
2040                         public bool RoundEffectiveDigits (int digits)
2041                         {
2042                                 return RoundEffectiveDigits (digits, true, true);
2043                         }
2044                         public bool RoundEffectiveDigits (int digits, bool carryFive, bool carryEven)
2045                         {
2046                                 bool carry = false;
2047
2048                                 if (digits >= _digits.Length || digits < 0)
2049                                         return false;
2050
2051                                 if (digits + 1 < _digits.Length && _digits [digits + 1] == 5 && _digits [digits] % 2 == (carryEven ? 0 : 1))
2052                                         carryFive = false;
2053
2054                                 /// are we cutting from the maximum precision ?
2055                                 if (_digits.Length == _defMaxPrecision) {
2056                                         // special case if we *aren't* cutting inside the extra precision (e.g. 16 on 17)
2057                                         if (digits != _defMaxPrecision - 1) {
2058                                                 // ok, here we look at the *two* extra numbers we're keeping
2059                                                 // (we keep 17 digits while the true precision is 15 digits).
2060                                                 int extra = _digits[_defMaxPrecision - 2] * 10 + _digits[_defMaxPrecision - 1];
2061                                                 carry = (extra >= 50);
2062                                                 if (carry) {
2063                                                         _digits[_defMaxPrecision - 2] = 0;
2064                                                         _digits[_defMaxPrecision - 1] = 0;
2065                                                         int d = _digits.Length - 3;
2066                                                         CarryPropagation (ref d, carryFive, ref carry);
2067                                                 }
2068                                         }
2069                                 }
2070                                 CarryPropagation (ref digits, carryFive, ref carry);
2071
2072                                 for (int i = digits; i < _digits.Length; i++)
2073                                         _digits [i] = 0;
2074                                 TrimDecimalEndZeros ();
2075
2076                                 return carry;
2077                         }
2078
2079                         private void CarryPropagation (ref int digits, bool carryFive, ref bool carry)
2080                         {
2081                                 for (int i = digits; i >= 0; i--) {
2082                                         RoundHelper (i, carryFive, ref carry);
2083                                         if (!carry)
2084                                                 break;
2085                                 }
2086
2087                                 if (carry) {
2088                                         byte[] temp = new byte[_digits.Length + 1];
2089                                         _digits.CopyTo (temp, 1);
2090                                         temp[0] = 1;
2091                                         _digits = temp;
2092                                         _decPointPos++;
2093                                         digits++;
2094                                 }
2095                         }
2096
2097                         #endregion
2098
2099                         #region Trim
2100                         public void TrimDecimalEndZeros ()
2101                         {
2102                                 int len = 0;
2103                                 for (int i = _digits.Length - 1; i >= 0; i --) {
2104                                         if (_digits [i] != 0)
2105                                                 break;
2106                                         len ++;
2107                                 }
2108
2109                                 if (len > 0) {
2110                                         byte[] temp = new byte [_digits.Length - len];
2111                                         Array.Copy (_digits, 0, temp, 0, temp.Length);
2112                                         _digits = temp;
2113                                 }
2114                         }
2115                         public void TrimIntegerStartZeros ()
2116                         {
2117                                 if (_decPointPos < 0 && _decPointPos >= _digits.Length)
2118                                         return;
2119
2120                                 int len = 0;
2121                                 for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
2122                                         if (_digits [i] != 0)
2123                                                 break;
2124                                         len ++;
2125                                 }
2126
2127                                 if (len == _decPointPos)
2128                                         len --;
2129
2130                                 if (len == _digits.Length) {
2131                                         _digits = new byte [1];
2132                                         _digits [0] = 0;
2133                                         _decPointPos = 1;
2134                                         _positive = true;
2135                                 } else if (len > 0) {
2136                                         byte[] temp = new byte [_digits.Length - len];
2137                                         Array.Copy (_digits, len, temp, 0, temp.Length);
2138                                         _digits = temp;
2139                                         _decPointPos -= len;
2140                                 }
2141                         }
2142
2143                         #endregion
2144
2145                         #region Integer
2146                         public void AppendIntegerString (int minLength, StringBuilder cb)
2147                         {
2148                                 if (IntegerDigits == 0) {
2149                                         cb.Append ('0', minLength);
2150                                         return;
2151                                 }
2152                                 if (_decPointPos <= 0) {
2153                                         cb.Append ('0', minLength);
2154                                         return;
2155                                 }
2156
2157                                 if (_decPointPos < minLength)
2158                                         cb.Append ('0', minLength - _decPointPos);
2159
2160                                 for (int i = 0; i < _decPointPos; i++) {
2161                                         if (i < _digits.Length)
2162                                                 cb.Append ((char)('0' + _digits [i]));
2163                                         else
2164                                                 cb.Append ('0');
2165                                 }
2166                         }
2167                         public void AppendIntegerStringWithGroupSeparator (StringBuilder sb, int[] groups, string groupSeparator)
2168                         {
2169                                 if (_decPointPos <= 0) {
2170                                         sb.Append ('0');
2171                                         return;
2172                                 }
2173
2174                                 int intLen = IntegerDigits;
2175                                 int total = 0;
2176                                 int groupIndex = 0;
2177                                 for (int i = 0; i < groups.Length; i++) {
2178                                         total += groups [i];
2179                                         if (total <= intLen)
2180                                                 groupIndex = i;
2181                                 }
2182
2183                                 if (groups.Length > 0 && total > 0) {
2184                                         int counter;
2185                                         int groupSize = groups [groupIndex];
2186                                         int fraction = intLen > total ? intLen - total : 0;
2187                                         if (groupSize == 0) {
2188                                                 while (groupIndex >= 0 && groups [groupIndex] == 0)
2189                                                         groupIndex --;
2190                                                 
2191                                                 groupSize = fraction > 0 ? fraction : groups [groupIndex];
2192                                         }
2193                                         if (fraction == 0) {
2194                                                 counter = groupSize;
2195                                         } else {
2196                                                 groupIndex += fraction / groupSize;
2197                                                 counter = fraction % groupSize;
2198                                                 if (counter == 0)
2199                                                         counter = groupSize;
2200                                                 else
2201                                                         groupIndex ++;
2202                                         }
2203                                         
2204                                         for (int i = 0; i < _decPointPos; i++) {
2205                                                 if (i < _digits.Length) {
2206                                                         sb.Append ((char)('0' + _digits [i]));
2207                                                 } else {
2208                                                         sb.Append ('0');
2209                                                 }
2210
2211                                                 if (i < intLen - 1 && --counter == 0) {
2212                                                         sb.Append (groupSeparator);
2213                                                         if (--groupIndex < groups.Length && groupIndex >= 0)
2214                                                                 groupSize = groups [groupIndex];
2215                                                         counter = groupSize;
2216                                                 }
2217                                         }
2218                                 } else {
2219                                         for (int i = 0; i < _decPointPos; i++) {
2220                                                 if (i < _digits.Length) {
2221                                                         sb.Append ((char)('0' + _digits [i]));
2222                                                 } else {
2223                                                         sb.Append ('0');
2224                                                 }
2225                                         }
2226                                 }
2227                         }
2228                         #endregion
2229
2230                         #region Decimal
2231                         public string GetDecimalString (int precision)
2232                         {
2233                                 if (!HasDecimal)
2234                                         return new string ('0', precision);
2235
2236                                 StringBuilder sb = new StringBuilder (precision);
2237                                 for (int i = _decPointPos; i < _digits.Length && i < precision + _decPointPos; i++) {
2238                                         if (i >= 0)
2239                                                 sb.Append ((char)('0' + _digits [i]));
2240                                         else
2241                                                 sb.Append ('0');
2242                                 }
2243                                 if (sb.Length < precision)
2244                                         sb.Append ('0', precision - sb.Length);
2245                                 else if (sb.Length > precision)
2246                                         sb.Remove (0, precision);
2247                                 return sb.ToString ();
2248                         }
2249
2250                         public void AppendDecimalString (int precision, StringBuilder cb)
2251                         {
2252                                 if (!HasDecimal) {
2253                                         cb.Append ('0', precision);
2254                                         return;
2255                                 }
2256
2257                                 int i = _decPointPos;
2258                                 for (; i < _digits.Length && i < precision + _decPointPos; i++) {
2259                                         if (i >= 0)
2260                                                 cb.Append ((char)('0' + _digits [i]));
2261                                         else
2262                                                 cb.Append ('0');
2263                                 }
2264
2265                                 i -= _decPointPos;
2266                                 if (i < precision)
2267                                         cb.Append ('0', precision - i);
2268                         }
2269                         #endregion
2270
2271                         #region others
2272                         public bool CheckZeroOnlyInteger ()
2273                         {
2274                                 for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
2275                                         if (_digits [i] != 0)
2276                                                 return false;
2277                                 }
2278                                 return true;
2279                         }
2280                         public void Multiply10 (int count)
2281                         {
2282                                 if (count <= 0)
2283                                         return;
2284
2285                                 _decPointPos += count;
2286
2287                                 TrimIntegerStartZeros ();
2288                         }
2289                         public void Divide10 (int count)
2290                         {
2291                                 if (count <= 0)
2292                                         return;
2293
2294                                 _decPointPos -= count;
2295                         }
2296                         public override string ToString()
2297                         {
2298                                 StringBuilder sb = new StringBuilder ();
2299                                 AppendIntegerString (IntegerDigits, sb);
2300                                 if (HasDecimal) {
2301                                         sb.Append ('.');
2302                                         AppendDecimalString (DecimalDigits, sb);
2303                                 }
2304                                 return sb.ToString ();
2305                         }
2306                         public char GetChar (int pos)
2307                         {
2308                                 if (_decPointPos <= 0)
2309                                         pos += _decPointPos - 1;
2310                                 
2311                                 if (pos < 0 || pos >= _digits.Length)
2312                                         return '0';
2313                                 else
2314                                         return (char)('0' + _digits [pos]);
2315                         }
2316                         public byte GetDigitByte (int pos)
2317                         {
2318                                 if (_decPointPos <= 0)
2319                                         pos += _decPointPos - 1;
2320                                 
2321                                 if (pos < 0 || pos >= _digits.Length)
2322                                         return 0;
2323                                 else
2324                                         return _digits [pos];
2325                         }
2326                         public NumberStore GetClone ()
2327                         {
2328                                 NumberStore ns = new NumberStore ();
2329
2330                                 ns._decPointPos = this._decPointPos;
2331                                 ns._defMaxPrecision = this._defMaxPrecision;
2332                                 ns._defPrecision = this._defPrecision;
2333                                 ns._digits = (byte[])this._digits.Clone ();
2334                                 ns._infinity = this._infinity;
2335                                 ns._NaN = this._NaN;
2336                                 ns._positive = this._positive;
2337
2338                                 return ns;
2339                         }
2340                         public int GetDecimalPointPos ()
2341                         {
2342                                 return _decPointPos;
2343                         }
2344                         public void SetDecimalPointPos (int dp)
2345                         {
2346                                 _decPointPos = dp;
2347                         }
2348                         #endregion
2349
2350                         #endregion
2351
2352                         #region Public Static Method
2353                         public static bool IsZeroOnly (StringBuilder sb)
2354                         {
2355                                 for (int i = 0; i < sb.Length; i++)
2356                                         if (char.IsDigit (sb [i]) && sb [i] != '0')
2357                                                 return false;
2358                                 return true;
2359                         }
2360                         public static void AppendIntegerStringFromUInt32 (StringBuilder sb, uint v)
2361                         {
2362                                 if (v < 0)
2363                                         throw new ArgumentException ();
2364
2365                                 int i = 9;
2366
2367                                 if (v >= 1000000000)
2368                                         i = 9;
2369                                 else if (v >= 100000000)
2370                                         i = 8;
2371                                 else if (v >= 10000000)
2372                                         i = 7;
2373                                 else if (v >= 1000000)
2374                                         i = 6;
2375                                 else if (v >= 100000)
2376                                         i = 5;
2377                                 else if (v >= 10000)
2378                                         i = 4;
2379                                 else if (v >= 1000)
2380                                         i = 3;
2381                                 else if (v >= 100)
2382                                         i = 2;
2383                                 else if (v >= 10)
2384                                         i = 1;
2385                                 else
2386                                         i = 0;
2387                                 do {
2388                                         uint n = v / IntList [i];
2389                                         sb.Append (NumberFormatter.digitLowerTable [n]);
2390                                         v -= IntList [i--] * n;
2391                                 } while (i >= 0);
2392                         }
2393                         #endregion
2394                 }
2395                 #endregion
2396         }
2397 }