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