percision -> precision in 446 places
[mono.git] / mcs / class / corlib / System / IntegerFormatter.cs
1 //
2 // System.IntegerFormatter.cs
3 //
4 // Author:
5 //   Derek Holden  (dholden@draper.com)
6 //
7 // (C) Derek Holden  dholden@draper.com
8 //
9
10 //
11 // Format integer types. Completely based off ECMA docs
12 // for IFormattable specification. Has been tested w/ 
13 // all integral types, from boundry to boundry, w/ all 
14 // formats A## ("G", "G0" ... "G99", "P", "P0" ... "P99").
15 //
16 // If you make any changes, please make sure to check the
17 // boundry format precisions (0, 99) and the min / max values
18 // of the data types (Int32.[Max/Min]Value).
19 //
20 // Using int as an example, it is currently set up as
21 //
22 // Int32 {
23 //   int value;
24 //   public string ToString (string format, NumberFormatInfo nfi) {
25 //      return IntegerFormatter.NumberToString (format, nfi, value);
26 //   }
27 //
28 // IntegerFormatter {
29 //   public string NumberToString (string format, NumberFormatInfo nfi, int value) {
30 //      ParseFormat (format);
31 //      switch (format type) {
32 //        case 'G' FormatGeneral(value, precision);
33 //        case 'R' throw Exception("Invalid blah blah");
34 //        case 'C' FromatCurrency(value, precision, nfi);
35 //        etc...
36 //      }
37 //   }
38 // }
39 //
40 // For every integral type.
41 //
42 // Before every Format<Format Type> block there is a small paragraph
43 // detailing its requirements, and a blurb of what I was thinking
44 // at the time.
45 //
46 // Some speedup suggestions to be done when after this appears
47 // to be working properly:
48 //
49 //   * Deal w/ out of range numbers better. Specifically with
50 //     regards to boundry cases such as Long.MinValue etc.
51 //     The previous way of if (value < 0) value = -value;
52 //     fails under this assumption, since the largest
53 //     possible MaxValue is < absolute value of the MinValue.
54 //     I do the first iteration outside of the loop, and then
55 //     convert the number to positive, then continue in the loop.
56 //
57 //   * Replace all occurances of max<Type>Length with their 
58 //     numerical values. Plus the places where things are set
59 //     to max<Type>Length - 1. Hardcode these to numbers.
60 //
61 //   * Move the code for all the NumberToString()'s into the
62 //     the main ToString (string, NumberFormatInfo) method in
63 //     the data types themselves. That way they'd be throwing
64 //     their own exceptions on error and it'd save a function
65 //     call.
66 //
67 //   * For integer to char buffer transformation, you could
68 //     implement the calculations of the 10's and 100's place
69 //     the same time w/ another table to shorten loop time.
70 //
71 //   * Someone smarter can prolly find a much more efficient 
72 //     way of formatting the exponential notation. It's still
73 //     done in pass, just may have too many repositioning
74 //     calculations.
75 //   
76 //   * Decide whether it be better to have functions that
77 //     handle formatting for all types, or just cast their
78 //     values out and format them. Just if library size is
79 //     more important than speed in saving a cast and a 
80 //     function call.
81 //
82
83 using System.Globalization;
84
85 namespace System {
86
87         internal sealed class IntegerFormatter {
88
89                 private static int maxByteLength = 4;
90                 private static int maxShortLength = 6;
91                 private static int maxIntLength = 12;
92                 private static int maxLongLength = 22;
93
94                 private static char[] digitLowerTable = 
95                 { '0', '1', '2', '3', '4', '5', '6', '7', 
96                   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
97
98                 private static char[] digitUpperTable = 
99                 { '0', '1', '2', '3', '4', '5', '6', '7', 
100                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
101
102                 private static bool ParseFormat (string format, out char specifier,  out int precision)
103                 {                                
104                         precision = -1;
105                         specifier = '\0';
106                         
107                         int length = format.Length;
108                         if (length < 1 || length > 3)
109                                 return false;
110                         
111                         char[] chars = format.ToCharArray ();
112                         specifier = chars[0];
113
114                         if (length == 1) 
115                                 return true;
116                         
117                         if (length == 2) {
118                                 if (chars[1] < '0' || chars[1] > '9')
119                                         return false;
120                                 
121                                 precision = chars[1] - '0';
122                         } else {
123                                 if (chars[1] < '0' || chars[2] < '0' || chars[1] > '9' || chars[2] > '9')
124                                         return false;
125                                 
126                                 precision = (chars[1] - '0') * 10 + (chars[2] - '0');
127                         }
128                         
129                         return true;
130                 }        
131
132                 // ============ Public Interface to all the integer types ============ //
133                 
134                 public static string NumberToString (string format, NumberFormatInfo nfi, byte value)
135                 {
136                         char specifier;
137                         int precision;
138                         
139                         if (!ParseFormat (format, out specifier, out precision))
140                                 throw new FormatException ("The specified format is invalid");
141
142                         switch(specifier) {
143                         case 'c': return FormatCurrency (value, precision, nfi);
144                         case 'C': return FormatCurrency (value, precision, nfi);
145                         case 'd': return FormatDecimal (value, precision);
146                         case 'D': return FormatDecimal (value, precision);
147                         case 'e': return FormatExponential (value, precision, false);
148                         case 'E': return FormatExponential (value, precision, true);
149                         case 'f': return FormatFixedPoint (value, precision, nfi);      
150                         case 'F': return FormatFixedPoint (value, precision, nfi);      
151                         case 'g': return FormatGeneral (value, precision, nfi, false);
152                         case 'G': return FormatGeneral (value, precision, nfi, true);
153                         case 'n': return FormatNumber (value, precision, nfi);
154                         case 'N': return FormatNumber (value, precision, nfi);
155                         case 'p': return FormatPercent (value, precision, nfi);
156                         case 'P': return FormatPercent (value, precision, nfi);
157                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
158                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
159                         case 'x': return FormatHexadecimal (value, precision, false);
160                         case 'X': return FormatHexadecimal (value, precision, true);
161                         default: 
162                                 throw new FormatException ("The specified format is invalid");
163                         }
164                 }               
165
166                 public static string NumberToString (string format, NumberFormatInfo nfi, short value)
167                 {
168                         char specifier;
169                         int precision;
170                         
171                         if (!ParseFormat (format, out specifier, out precision))
172                                 throw new FormatException ("The specified format is invalid");
173
174                         switch(specifier) {
175                         case 'c': return FormatCurrency (value, precision, nfi);
176                         case 'C': return FormatCurrency (value, precision, nfi);
177                         case 'd': return FormatDecimal (value, precision);
178                         case 'D': return FormatDecimal (value, precision);
179                         case 'e': return FormatExponential (value, precision, false);
180                         case 'E': return FormatExponential (value, precision, true);
181                         case 'f': return FormatFixedPoint (value, precision, nfi);      
182                         case 'F': return FormatFixedPoint (value, precision, nfi);      
183                         case 'g': return FormatGeneral (value, precision, nfi, false);
184                         case 'G': return FormatGeneral (value, precision, nfi, true);
185                         case 'n': return FormatNumber (value, precision, nfi);
186                         case 'N': return FormatNumber (value, precision, nfi);
187                         case 'p': return FormatPercent (value, precision, nfi);
188                         case 'P': return FormatPercent (value, precision, nfi);
189                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
190                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
191                         case 'x': return FormatHexadecimal (value, precision, false);
192                         case 'X': return FormatHexadecimal (value, precision, true);
193                         default: 
194                                 throw new FormatException ("The specified format is invalid");
195                         }
196                 }
197
198                 public static string NumberToString (string format, NumberFormatInfo nfi, int value)
199                 {
200                         char specifier;
201                         int precision;
202                         
203                         if (!ParseFormat (format, out specifier, out precision))
204                                 throw new FormatException ("The specified format is invalid");
205                         
206                         switch(specifier) {
207                         case 'c': return FormatCurrency (value, precision, nfi);        
208                         case 'C': return FormatCurrency (value, precision, nfi);        
209                         case 'd': return FormatDecimal (value, precision);
210                         case 'D': return FormatDecimal (value, precision);
211                         case 'e': return FormatExponential (value, precision, false);
212                         case 'E': return FormatExponential (value, precision, true);
213                         case 'f': return FormatFixedPoint (value, precision, nfi);      
214                         case 'F': return FormatFixedPoint (value, precision, nfi);      
215                         case 'g': return FormatGeneral (value, precision, nfi, false);
216                         case 'G': return FormatGeneral (value, precision, nfi, true);
217                         case 'n': return FormatNumber (value, precision, nfi);
218                         case 'N': return FormatNumber (value, precision, nfi);
219                         case 'p': return FormatPercent (value, precision, nfi);
220                         case 'P': return FormatPercent (value, precision, nfi);
221                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
222                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
223                         case 'x': return FormatHexadecimal (value, precision, false);
224                         case 'X': return FormatHexadecimal (value, precision, true);
225                         default: 
226                                 throw new FormatException ("The specified format is invalid");
227                         }
228                 }
229
230                 public static string NumberToString (string format, NumberFormatInfo nfi, long value)
231                 {
232                         char specifier;
233                         int precision;
234                         
235                         if (!ParseFormat (format, out specifier, out precision))
236                                 throw new FormatException ("The specified format is invalid");
237                         
238                         switch(specifier) {
239                         case 'c': return FormatCurrency (value, precision, nfi);
240                         case 'C': return FormatCurrency (value, precision, nfi);
241                         case 'd': return FormatDecimal (value, precision);
242                         case 'D': return FormatDecimal (value, precision);
243                         case 'e': return FormatExponential (value, precision, false);
244                         case 'E': return FormatExponential (value, precision, true);
245                         case 'f': return FormatFixedPoint (value, precision, nfi);      
246                         case 'F': return FormatFixedPoint (value, precision, nfi);      
247                         case 'g': return FormatGeneral (value, precision, nfi, false);
248                         case 'G': return FormatGeneral (value, precision, nfi, true);
249                         case 'n': return FormatNumber (value, precision, nfi);
250                         case 'N': return FormatNumber (value, precision, nfi);
251                         case 'p': return FormatPercent (value, precision, nfi);
252                         case 'P': return FormatPercent (value, precision, nfi);
253                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
254                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
255                         case 'x': return FormatHexadecimal (value, precision, false);
256                         case 'X': return FormatHexadecimal (value, precision, true);
257                         default: 
258                                 throw new FormatException ("The specified format is invalid");
259                         }                       
260                 }
261
262                 public static string NumberToString (string format, NumberFormatInfo nfi, sbyte value)
263                 {
264                         char specifier;
265                         int precision;
266                         
267                         if (!ParseFormat (format, out specifier, out precision))
268                                 throw new FormatException ("The specified format is invalid");
269                         
270                         switch(specifier) {
271                         case 'c': return FormatCurrency (value, precision, nfi);
272                         case 'C': return FormatCurrency (value, precision, nfi);
273                         case 'd': return FormatDecimal (value, precision);
274                         case 'D': return FormatDecimal (value, precision);
275                         case 'e': return FormatExponential (value, precision, false);
276                         case 'E': return FormatExponential (value, precision, true);
277                         case 'f': return FormatFixedPoint (value, precision, nfi);      
278                         case 'F': return FormatFixedPoint (value, precision, nfi);      
279                         case 'g': return FormatGeneral (value, precision, nfi, false);
280                         case 'G': return FormatGeneral (value, precision, nfi, true);
281                         case 'n': return FormatNumber (value, precision, nfi);
282                         case 'N': return FormatNumber (value, precision, nfi);
283                         case 'p': return FormatPercent (value, precision, nfi);
284                         case 'P': return FormatPercent (value, precision, nfi);
285                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
286                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
287                         case 'x': return FormatHexadecimal (value, precision, false);
288                         case 'X': return FormatHexadecimal (value, precision, true);
289                         default: 
290                                 throw new FormatException ("The specified format is invalid");
291                         }
292                 }
293
294                 public static string NumberToString (string format, NumberFormatInfo nfi, ushort value)
295                 {
296                         char specifier;
297                         int precision;
298                         
299                         if (!ParseFormat (format, out specifier, out precision))
300                                 throw new FormatException ("The specified format is invalid");
301                         
302                         switch(specifier) {
303                         case 'c': return FormatCurrency (value, precision, nfi);
304                         case 'C': return FormatCurrency (value, precision, nfi);
305                         case 'd': return FormatDecimal (value, precision);
306                         case 'D': return FormatDecimal (value, precision);
307                         case 'e': return FormatExponential (value, precision, false);
308                         case 'E': return FormatExponential (value, precision, true);
309                         case 'f': return FormatFixedPoint (value, precision, nfi);      
310                         case 'F': return FormatFixedPoint (value, precision, nfi);      
311                         case 'g': return FormatGeneral (value, precision, nfi, false);
312                         case 'G': return FormatGeneral (value, precision, nfi, true);
313                         case 'n': return FormatNumber (value, precision, nfi);
314                         case 'N': return FormatNumber (value, precision, nfi);
315                         case 'p': return FormatPercent (value, precision, nfi);
316                         case 'P': return FormatPercent (value, precision, nfi);
317                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
318                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
319                         case 'x': return FormatHexadecimal (value, precision, false);
320                         case 'X': return FormatHexadecimal (value, precision, true);
321                         default: 
322                                 throw new FormatException ("The specified format is invalid");
323                         }
324                 }
325
326                 public static string NumberToString (string format, NumberFormatInfo nfi, uint value)
327                 {
328                         char specifier;
329                         int precision;
330                         
331                         if (!ParseFormat (format, out specifier, out precision))
332                                 throw new FormatException ("The specified format is invalid");
333                         
334                         switch(specifier) {
335                         case 'c': return FormatCurrency (value, precision, nfi);
336                         case 'C': return FormatCurrency (value, precision, nfi);
337                         case 'd': return FormatDecimal (value, precision);
338                         case 'D': return FormatDecimal (value, precision);
339                         case 'e': return FormatExponential (value, precision, false);
340                         case 'E': return FormatExponential (value, precision, true);
341                         case 'f': return FormatFixedPoint (value, precision, nfi);      
342                         case 'F': return FormatFixedPoint (value, precision, nfi);      
343                         case 'g': return FormatGeneral (value, precision, nfi, false);
344                         case 'G': return FormatGeneral (value, precision, nfi, true);
345                         case 'n': return FormatNumber (value, precision, nfi);
346                         case 'N': return FormatNumber (value, precision, nfi);
347                         case 'p': return FormatPercent (value, precision, nfi);
348                         case 'P': return FormatPercent (value, precision, nfi);
349                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
350                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
351                         case 'x': return FormatHexadecimal (value, precision, false);
352                         case 'X': return FormatHexadecimal (value, precision, true);
353                         default: 
354                                 throw new FormatException ("The specified format is invalid");
355                         }
356                 }
357
358                 public static string NumberToString (string format, NumberFormatInfo nfi, ulong value)
359                 {
360                         char specifier;
361                         int precision;
362                         
363                         if (!ParseFormat (format, out specifier, out precision))
364                                 throw new FormatException ("The specified format is invalid");
365                         
366                         switch(specifier) {
367                         case 'c': return FormatCurrency (value, precision, nfi);
368                         case 'C': return FormatCurrency (value, precision, nfi);
369                         case 'd': return FormatDecimal (value, precision);
370                         case 'D': return FormatDecimal (value, precision);
371                         case 'e': return FormatExponential (value, precision, false);
372                         case 'E': return FormatExponential (value, precision, true);
373                         case 'f': return FormatFixedPoint (value, precision, nfi);      
374                         case 'F': return FormatFixedPoint (value, precision, nfi);      
375                         case 'g': return FormatGeneral (value, precision, nfi, false);
376                         case 'G': return FormatGeneral (value, precision, nfi, true);
377                         case 'n': return FormatNumber (value, precision, nfi);
378                         case 'N': return FormatNumber (value, precision, nfi);
379                         case 'p': return FormatPercent (value, precision, nfi);
380                         case 'P': return FormatPercent (value, precision, nfi);
381                         case 'r': throw new FormatException ("The specified format cannot be used in this instance");
382                         case 'R': throw new FormatException ("The specified format cannot be used in this instance");
383                         case 'x': return FormatHexadecimal (value, precision, false);
384                         case 'X': return FormatHexadecimal (value, precision, true);
385                         default: 
386                                 throw new FormatException ("The specified format is invalid");
387                         }
388                 }
389
390                 // ============ Currency Type Formating ============ //
391
392                 //
393                 //  Currency Format: Used for strings containing a monetary value. The
394                 //  CurrencySymbol, CurrencyGroupSizes, CurrencyGroupSeparator, and
395                 //  CurrencyDecimalSeparator members of a NumberFormatInfo supply
396                 //  the currency symbol, size and separator for digit groupings, and
397                 //  decimal separator, respectively.
398                 //  CurrencyNegativePattern and CurrencyPositivePattern determine the
399                 //  symbols used to represent negative and positive values. For example,
400                 //  a negative value may be prefixed with a minus sign, or enclosed in
401                 //  parentheses.
402                 //  If the precision specifier is omitted
403                 //  NumberFormatInfo.CurrencyDecimalDigits determines the number of
404                 //  decimal places in the string. Results are rounded to the nearest
405                 //  representable value when necessary.
406                 //
407                 //  The pattern of the NumberFormatInfo determines how the output looks, where
408                 //  the dollar sign goes, where the negative sign goes, etc.
409                 //  IFormattable documentation lists the patterns and their values,
410                 //  I have them commented out in the large switch statement
411                 //
412
413                 private static string FormatCurrency (byte value, int precision, NumberFormatInfo nfi) 
414                 {
415                         return FormatCurrency ((uint)value, precision, nfi);
416                 }
417
418                 private static string FormatCurrency (short value, int precision, NumberFormatInfo nfi) 
419                 {
420                         return FormatCurrency ((int)value, precision, nfi);                     
421                 }
422                         
423                 private static string FormatCurrency (int value, int precision, NumberFormatInfo nfi) 
424                 {
425                         int i, j, k;
426                         bool negative = (value < 0);
427
428                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
429                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
430                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
431                         int[] groupSizes = nfi.CurrencyGroupSizes;
432                         int pattern = negative ? nfi.CurrencyNegativePattern : nfi.CurrencyPositivePattern;
433                         int symbolLength = currencySymbol.Length;
434                         
435                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
436                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
437                         decimalSeparator.Length + symbolLength; 
438                         char[] buffy = new char[size];
439                         int position = size;
440
441                         // set up the pattern from IFormattible
442                         if (negative) {
443                                 i = symbolLength; 
444  
445                                 switch (pattern) {
446                                 case 0: // ($nnn)
447                                         buffy[--position] = ')'; 
448                                         break;
449                                 // case 1: // -$nnn
450                                 //      break;
451                                 // case 2: // $-nnn
452                                 //      break;
453                                 case 3: // $nnn-
454                                         buffy[--position] = '-';
455                                         break;
456                                 case 4: // (nnn$)
457                                         buffy[--position] = ')'; 
458                                         do {
459                                                 buffy[--position] = currencySymbol[--i];
460                                         } while (i > 0);
461                                         break;
462                                 case 5: // -nnn$
463                                         do {
464                                                 buffy[--position] = currencySymbol[--i];
465                                         } while (i > 0);
466                                         break;
467                                 case 6: // nnn-$
468                                         do {
469                                                 buffy[--position] = currencySymbol[--i];
470                                         } while (i > 0);
471                                         buffy[--position] = '-'; 
472                                         break;
473                                 case 7: // nnn$-
474                                         buffy[--position] = '-'; 
475                                         do {
476                                                 buffy[--position] = currencySymbol[--i];
477                                         } while (i > 0);
478                                         break;
479                                 case 8: // -nnn $
480                                         do {
481                                                 buffy[--position] = currencySymbol[--i];
482                                         } while (i > 0);
483                                         buffy[--position] = ' '; 
484                                         break;
485                                 // case 9: // -$ nnn
486                                 //      break;
487                                 case 10: // nnn $-
488                                         buffy[--position] = '-'; 
489                                         do {
490                                                 buffy[--position] = currencySymbol[--i];
491                                         } while (i > 0);
492                                         buffy[--position] = ' '; 
493                                         break;
494                                 case 11: // $ nnn-
495                                         buffy[--position] = '-'; 
496                                         break;
497                                 // case 12: // $ -nnn
498                                 //      break;
499                                 case 13: // nnn- $
500                                         do {
501                                                 buffy[--position] = currencySymbol[--i];
502                                         } while (i > 0);
503                                         buffy[--position] = ' '; 
504                                         buffy[--position] = '-'; 
505                                         break;
506                                 case 14: // ($ nnn)
507                                         buffy[--position] = ')'; 
508                                         break;
509                                 case 15: // (nnn $)
510                                         buffy[--position] = ')'; 
511                                         do {
512                                                 buffy[--position] = currencySymbol[--i];
513                                         } while (i > 0);
514                                         break;                          
515                                 }
516                         } else {
517                                 i = symbolLength; 
518                                 switch (pattern) {
519                                 // case 0: // $nnn
520                                 //      break;
521                                 case 1: // nnn$
522                                         do {
523                                                 buffy[--position] = currencySymbol[--i];
524                                         } while (i > 0);
525                                         break;
526                                 // case 2: // $ nnn
527                                 //      break;
528                                 case 3: // nnn $
529                                         do {
530                                                 buffy[--position] = currencySymbol[--i];
531                                         } while (i > 0);
532                                         buffy[--position] = ' '; 
533                                         break;
534                                 }
535                         }
536                         
537                         // right pad it w/ precision 0's
538                         while (padding-- > 0)
539                                 buffy[--position] = '0';
540
541                         // put on decimal separator if we moved over and put a 0 
542                         if (position < size && buffy[position] == '0') {
543                                 i = decimalSeparator.Length; 
544                                 do {
545                                         buffy[--position] = decimalSeparator[--i];
546                                 } while (i > 0);                        
547                         }
548
549                         // loop through, keeping track of where you are in the
550                         // group sizes array and putting out the group separator
551                         // when needed
552                         j = 0;
553                         k = groupSizes[j++];
554
555                         // just in place to take care of the negative boundries (Int32.MinValue)
556                         if (negative) {
557                                 if (value <= -10) {
558                                         buffy[--position] = digitLowerTable[-(value % 10)];
559                                         value = value / -10;
560                                         
561                                         if (--k == 0) {
562                                                 i = groupSeparator.Length; 
563                                                 do {
564                                                         buffy[--position] = groupSeparator[--i];
565                                                 } while (i > 0);
566                                                 
567                                                 k = (j < groupSizes.Length) ? 
568                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
569                                         }
570                                 } else value = -value;
571                         }
572
573                         while (value >= 10) {
574                                 buffy[--position] = digitLowerTable[(value % 10)];
575                                 value /= 10;
576
577                                 if (--k == 0) {
578                                         i = groupSeparator.Length; 
579                                         do {
580                                                 buffy[--position] = groupSeparator[--i];
581                                         } while (i > 0);
582                                         
583                                         k = (j < groupSizes.Length) ? 
584                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
585                                 }
586                         }                
587
588                         buffy[--position] = digitLowerTable[value];
589
590                         // end the pattern on the left hand side
591                         if (negative) {
592                                 i = symbolLength; 
593  
594                                 switch (pattern) {
595                                 case 0: // ($nnn)
596                                         do {
597                                                 buffy[--position] = currencySymbol[--i];
598                                         } while (i > 0);
599                                         buffy[--position] = '('; 
600                                         break;
601                                 case 1: // -$nnn
602                                         do {
603                                                 buffy[--position] = currencySymbol[--i];
604                                         } while (i > 0);
605                                         buffy[--position] = '-'; 
606                                         break;
607                                 case 2: // $-nnn
608                                         buffy[--position] = '-'; 
609                                         do {
610                                                 buffy[--position] = currencySymbol[--i];
611                                         } while (i > 0);
612                                         break;
613                                 case 3: // $nnn-
614                                         do {
615                                                 buffy[--position] = currencySymbol[--i];
616                                         } while (i > 0);
617                                         break;
618                                 case 4: // (nnn$)
619                                         buffy[--position] = '('; 
620                                         break;
621                                 case 5: // -nnn$
622                                         buffy[--position] = '-'; 
623                                         break;
624                                 // case 6: // nnn-$
625                                 //      break;
626                                 // case 7: // nnn$-
627                                 //      break;
628                                 case 8: // -nnn $
629                                         buffy[--position] = '-'; 
630                                         break;
631                                 // case 9: // -$ nnn
632                                 //      break;
633                                 // case 10: // nnn $-
634                                 //      break;
635                                 case 11: // $ nnn-
636                                         buffy[--position] = ' '; 
637                                         do {
638                                                 buffy[--position] = currencySymbol[--i];
639                                         } while (i > 0);
640                                         break;
641                                 case 12: // $ -nnn
642                                         buffy[--position] = '-'; 
643                                         buffy[--position] = ' '; 
644                                         do {
645                                                 buffy[--position] = currencySymbol[--i];
646                                         } while (i > 0);
647                                         break;
648                                 // case 13: // nnn- $
649                                 //      break;
650                                 case 14: // ($ nnn)
651                                         buffy[--position] = ' '; 
652                                         do {
653                                                 buffy[--position] = currencySymbol[--i];
654                                         } while (i > 0);
655                                         buffy[--position] = '('; 
656                                         break;
657                                 case 15: // (nnn $)
658                                         buffy[--position] = '('; 
659                                         break;                          
660                                 }
661                         } else {
662                                 i = symbolLength; 
663                                 switch (pattern) {
664                                 case 0: // $nnn
665                                         do {
666                                                 buffy[--position] = currencySymbol[--i];
667                                         } while (i > 0);
668                                         break;
669                                 // case 1: // nnn$
670                                 //      break;
671                                 case 2: // $ nnn
672                                         buffy[--position] = ' '; 
673                                         do {
674                                                 buffy[--position] = currencySymbol[--i];
675                                         } while (i > 0);
676                                         break;
677                                 // case 3: // nnn $
678                                 //      break;
679                                 }
680                         }
681                         
682                         return new string (buffy, position, (size - position));
683                 }
684
685                 private static string FormatCurrency (long value, int precision, NumberFormatInfo nfi) 
686                 {
687                         int i, j, k;
688                         bool negative = (value < 0);
689
690                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
691                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
692                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
693                         int[] groupSizes = nfi.CurrencyGroupSizes;
694                         int pattern = negative ? nfi.CurrencyNegativePattern : nfi.CurrencyPositivePattern;
695                         int symbolLength = currencySymbol.Length;
696                         
697                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
698                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
699                         decimalSeparator.Length + symbolLength; 
700                         char[] buffy = new char[size];
701                         int position = size;
702
703                         // set up the pattern from IFormattible
704                         if (negative) {
705                                 i = symbolLength; 
706  
707                                 switch (pattern) {
708                                 case 0: // ($nnn)
709                                         buffy[--position] = ')'; 
710                                         break;
711                                 // case 1: // -$nnn
712                                 //      break;
713                                 // case 2: // $-nnn
714                                 //      break;
715                                 case 3: // $nnn-
716                                         buffy[--position] = '-';
717                                         break;
718                                 case 4: // (nnn$)
719                                         buffy[--position] = ')'; 
720                                         do {
721                                                 buffy[--position] = currencySymbol[--i];
722                                         } while (i > 0);
723                                         break;
724                                 case 5: // -nnn$
725                                         do {
726                                                 buffy[--position] = currencySymbol[--i];
727                                         } while (i > 0);
728                                         break;
729                                 case 6: // nnn-$
730                                         do {
731                                                 buffy[--position] = currencySymbol[--i];
732                                         } while (i > 0);
733                                         buffy[--position] = '-'; 
734                                         break;
735                                 case 7: // nnn$-
736                                         buffy[--position] = '-'; 
737                                         do {
738                                                 buffy[--position] = currencySymbol[--i];
739                                         } while (i > 0);
740                                         break;
741                                 case 8: // -nnn $
742                                         do {
743                                                 buffy[--position] = currencySymbol[--i];
744                                         } while (i > 0);
745                                         buffy[--position] = ' '; 
746                                         break;
747                                 // case 9: // -$ nnn
748                                 //      break;
749                                 case 10: // nnn $-
750                                         buffy[--position] = '-'; 
751                                         do {
752                                                 buffy[--position] = currencySymbol[--i];
753                                         } while (i > 0);
754                                         buffy[--position] = ' '; 
755                                         break;
756                                 case 11: // $ nnn-
757                                         buffy[--position] = '-'; 
758                                         break;
759                                 // case 12: // $ -nnn
760                                 //      break;
761                                 case 13: // nnn- $
762                                         do {
763                                                 buffy[--position] = currencySymbol[--i];
764                                         } while (i > 0);
765                                         buffy[--position] = ' '; 
766                                         buffy[--position] = '-'; 
767                                         break;
768                                 case 14: // ($ nnn)
769                                         buffy[--position] = ')'; 
770                                         break;
771                                 case 15: // (nnn $)
772                                         buffy[--position] = ')'; 
773                                         do {
774                                                 buffy[--position] = currencySymbol[--i];
775                                         } while (i > 0);
776                                         break;                          
777                                 }
778                         } else {
779                                 i = symbolLength; 
780                                 switch (pattern) {
781                                 // case 0: // $nnn
782                                 //      break;
783                                 case 1: // nnn$
784                                         do {
785                                                 buffy[--position] = currencySymbol[--i];
786                                         } while (i > 0);
787                                         break;
788                                 // case 2: // $ nnn
789                                 //      break;
790                                 case 3: // nnn $
791                                         do {
792                                                 buffy[--position] = currencySymbol[--i];
793                                         } while (i > 0);
794                                         buffy[--position] = ' '; 
795                                         break;
796                                 }
797                         }
798                         
799                         // right pad it w/ precision 0's
800                         while (padding-- > 0)
801                                 buffy[--position] = '0';
802
803                         // put on decimal separator if we moved over and put a 0 
804                         if (position < size && buffy[position] == '0') {
805                                 i = decimalSeparator.Length; 
806                                 do {
807                                         buffy[--position] = decimalSeparator[--i];
808                                 } while (i > 0);                        
809                         }
810
811                         // loop through, keeping track of where you are in the
812                         // group sizes array and putting out the group separator
813                         // when needed
814                         j = 0;
815                         k = groupSizes[j++];
816                        
817                         if (negative) {
818                                 if (value <= -10) {
819                                         buffy[--position] = digitLowerTable[-(value % 10)];
820                                         value = value / -10;
821                                         
822                                         if (--k == 0) {
823                                                 i = groupSeparator.Length; 
824                                                 do {
825                                                         buffy[--position] = groupSeparator[--i];
826                                                 } while (i > 0);
827                                                 
828                                                 k = (j < groupSizes.Length) ? 
829                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
830                                         }
831                                 } else value = -value;
832                         }
833
834                         while (value >= 10) {
835                                 buffy[--position] = digitLowerTable[(value % 10)];
836                                 value /= 10;
837
838                                 if (--k == 0) {
839                                         i = groupSeparator.Length; 
840                                         do {
841                                                 buffy[--position] = groupSeparator[--i];
842                                         } while (i > 0);
843                                         
844                                         k = (j < groupSizes.Length) ? 
845                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
846                                 }
847                         }                
848
849                         buffy[--position] = digitLowerTable[value];
850
851                         // end the pattern on the left hand side
852                         if (negative) {
853                                 i = symbolLength; 
854  
855                                 switch (pattern) {
856                                 case 0: // ($nnn)
857                                         do {
858                                                 buffy[--position] = currencySymbol[--i];
859                                         } while (i > 0);
860                                         buffy[--position] = '('; 
861                                         break;
862                                 case 1: // -$nnn
863                                         do {
864                                                 buffy[--position] = currencySymbol[--i];
865                                         } while (i > 0);
866                                         buffy[--position] = '-'; 
867                                         break;
868                                 case 2: // $-nnn
869                                         buffy[--position] = '-'; 
870                                         do {
871                                                 buffy[--position] = currencySymbol[--i];
872                                         } while (i > 0);
873                                         break;
874                                 case 3: // $nnn-
875                                         do {
876                                                 buffy[--position] = currencySymbol[--i];
877                                         } while (i > 0);
878                                         break;
879                                 case 4: // (nnn$)
880                                         buffy[--position] = '('; 
881                                         break;
882                                 case 5: // -nnn$
883                                         buffy[--position] = '-'; 
884                                         break;
885                                 // case 6: // nnn-$
886                                 //      break;
887                                 // case 7: // nnn$-
888                                 //      break;
889                                 case 8: // -nnn $
890                                         buffy[--position] = '-'; 
891                                         break;
892                                 // case 9: // -$ nnn
893                                 //      break;
894                                 // case 10: // nnn $-
895                                 //      break;
896                                 case 11: // $ nnn-
897                                         buffy[--position] = ' '; 
898                                         do {
899                                                 buffy[--position] = currencySymbol[--i];
900                                         } while (i > 0);
901                                         break;
902                                 case 12: // $ -nnn
903                                         buffy[--position] = '-'; 
904                                         buffy[--position] = ' '; 
905                                         do {
906                                                 buffy[--position] = currencySymbol[--i];
907                                         } while (i > 0);
908                                         break;
909                                 // case 13: // nnn- $
910                                 //      break;
911                                 case 14: // ($ nnn)
912                                         buffy[--position] = ' '; 
913                                         do {
914                                                 buffy[--position] = currencySymbol[--i];
915                                         } while (i > 0);
916                                         buffy[--position] = '('; 
917                                         break;
918                                 case 15: // (nnn $)
919                                         buffy[--position] = '('; 
920                                         break;                          
921                                 }
922                         } else {
923                                 i = symbolLength; 
924                                 switch (pattern) {
925                                 case 0: // $nnn
926                                         do {
927                                                 buffy[--position] = currencySymbol[--i];
928                                         } while (i > 0);
929                                         break;
930                                 // case 1: // nnn$
931                                 //      break;
932                                 case 2: // $ nnn
933                                         buffy[--position] = ' '; 
934                                         do {
935                                                 buffy[--position] = currencySymbol[--i];
936                                         } while (i > 0);
937                                         break;
938                                 // case 3: // nnn $
939                                 //      break;
940                                 }
941                         }
942                         
943                         return new string (buffy, position, (size - position));
944                 }
945
946                 private static string FormatCurrency (sbyte value, int precision, NumberFormatInfo nfi) 
947                 {
948                         return FormatCurrency ((int)value, precision, nfi);
949                 }
950
951                 private static string FormatCurrency (ushort value, int precision, NumberFormatInfo nfi) 
952                 {
953                         return FormatCurrency ((uint)value, precision, nfi);                    
954                 }
955
956                 private static string FormatCurrency (uint value, int precision, NumberFormatInfo nfi) 
957                 {
958                         int i, j, k;
959
960                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
961                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
962                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
963                         int[] groupSizes = nfi.CurrencyGroupSizes;
964                         int pattern = nfi.CurrencyPositivePattern;
965                         int symbolLength = currencySymbol.Length;
966                         
967                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
968                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
969                         decimalSeparator.Length + symbolLength; 
970                         char[] buffy = new char[size];
971                         int position = size;
972
973                         // set up the pattern from IFormattible, no negative
974                         i = symbolLength; 
975                         switch (pattern) {
976                         // case 0: // $nnn
977                         //      break;
978                         case 1: // nnn$
979                                 do {
980                                         buffy[--position] = currencySymbol[--i];
981                                 } while (i > 0);
982                                 break;
983                         // case 2: // $ nnn
984                         //      break;
985                         case 3: // nnn $
986                                 do {
987                                         buffy[--position] = currencySymbol[--i];
988                                 } while (i > 0);
989                                 buffy[--position] = ' '; 
990                                 break;
991                         }
992                         
993                         // right pad it w/ precision 0's
994                         while (padding-- > 0)
995                                 buffy[--position] = '0';
996
997                         // put on decimal separator if we moved over and put a 0 
998                         if (position < size && buffy[position] == '0') {
999                                 i = decimalSeparator.Length; 
1000                                 do {
1001                                         buffy[--position] = decimalSeparator[--i];
1002                                 } while (i > 0);                        
1003                         }
1004
1005                         // loop through, keeping track of where you are in the
1006                         // group sizes array and putting out the group separator
1007                         // when needed
1008                         j = 0;
1009                         k = groupSizes[j++];
1010                        
1011                         while (value >= 10) {
1012                                 buffy[--position] = digitLowerTable[(value % 10)];
1013                                 value /= 10;
1014
1015                                 if (--k == 0) {
1016                                         i = groupSeparator.Length; 
1017                                         do {
1018                                                 buffy[--position] = groupSeparator[--i];
1019                                         } while (i > 0);
1020                                         
1021                                         k = (j < groupSizes.Length) ? 
1022                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
1023                                 }
1024                         }                
1025
1026                         buffy[--position] = digitLowerTable[value];
1027
1028                         // end the pattern on the left hand side
1029                         i = symbolLength; 
1030                         switch (pattern) {
1031                         case 0: // $nnn
1032                                 do {
1033                                         buffy[--position] = currencySymbol[--i];
1034                                 } while (i > 0);
1035                                 break;
1036                         // case 1: // nnn$
1037                         //      break;
1038                         case 2: // $ nnn
1039                                 buffy[--position] = ' '; 
1040                                 do {
1041                                         buffy[--position] = currencySymbol[--i];
1042                                 } while (i > 0);
1043                                 break;
1044                         // case 3: // nnn $
1045                                 //      break;
1046                         }
1047                         
1048                         return new string (buffy, position, (size - position));
1049                 }
1050
1051                 private static string FormatCurrency (ulong value, int precision, NumberFormatInfo nfi) 
1052                 {
1053                         int i, j, k;
1054
1055                         char[] groupSeparator = nfi.CurrencyGroupSeparator.ToCharArray ();
1056                         char[] decimalSeparator = nfi.CurrencyDecimalSeparator.ToCharArray ();
1057                         char[] currencySymbol = nfi.CurrencySymbol.ToCharArray ();
1058                         int[] groupSizes = nfi.CurrencyGroupSizes;
1059                         int pattern = nfi.CurrencyPositivePattern;
1060                         int symbolLength = currencySymbol.Length;
1061                         
1062                         int padding = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;      
1063                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
1064                         decimalSeparator.Length + symbolLength; 
1065                         char[] buffy = new char[size];
1066                         int position = size;
1067
1068                         // set up the pattern from IFormattible, no negative
1069                         i = symbolLength; 
1070                         switch (pattern) {
1071                         // case 0: // $nnn
1072                         //      break;
1073                         case 1: // nnn$
1074                                 do {
1075                                         buffy[--position] = currencySymbol[--i];
1076                                 } while (i > 0);
1077                                 break;
1078                         // case 2: // $ nnn
1079                         //      break;
1080                         case 3: // nnn $
1081                                 do {
1082                                         buffy[--position] = currencySymbol[--i];
1083                                 } while (i > 0);
1084                                 buffy[--position] = ' '; 
1085                                 break;
1086                         }
1087                         
1088                         // right pad it w/ precision 0's
1089                         while (padding-- > 0)
1090                                 buffy[--position] = '0';
1091
1092                         // put on decimal separator if we moved over and put a 0 
1093                         if (position < size && buffy[position] == '0') {
1094                                 i = decimalSeparator.Length; 
1095                                 do {
1096                                         buffy[--position] = decimalSeparator[--i];
1097                                 } while (i > 0);                        
1098                         }
1099
1100                         // loop through, keeping track of where you are in the
1101                         // group sizes array and putting out the group separator
1102                         // when needed
1103                         j = 0;
1104                         k = groupSizes[j++];
1105                        
1106                         while (value >= 10) {
1107                                 buffy[--position] = digitLowerTable[(value % 10)];
1108                                 value /= 10;
1109
1110                                 if (--k == 0) {
1111                                         i = groupSeparator.Length; 
1112                                         do {
1113                                                 buffy[--position] = groupSeparator[--i];
1114                                         } while (i > 0);
1115                                         
1116                                         k = (j < groupSizes.Length) ? 
1117                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
1118                                 }
1119                         }                
1120
1121                         buffy[--position] = digitLowerTable[value];
1122
1123                         // end the pattern on the left hand side
1124                         i = symbolLength; 
1125                         switch (pattern) {
1126                         case 0: // $nnn
1127                                 do {
1128                                         buffy[--position] = currencySymbol[--i];
1129                                 } while (i > 0);
1130                                 break;
1131                         // case 1: // nnn$
1132                         //      break;
1133                         case 2: // $ nnn
1134                                 buffy[--position] = ' '; 
1135                                 do {
1136                                         buffy[--position] = currencySymbol[--i];
1137                                 } while (i > 0);
1138                                 break;
1139                         // case 3: // nnn $
1140                                 //      break;
1141                         }
1142                         
1143                         return new string (buffy, position, (size - position));
1144                 }
1145                 
1146                 // ============ Format Decimal Types ============ //
1147
1148                 //
1149                 // Used only for integral data types. Negative values are 
1150                 // represented by using a '-' sign. The precision specifies
1151                 // how many digits are to appear in the string. If it is >
1152                 // how many digits we need, the left side is padded w/ 0's.
1153                 // If it is smaller than what we need, it is discarded.
1154                 //
1155                 // Fairly simple implementation. Fill the buffer from right
1156                 // to left w/ numbers, then if we still have precision left
1157                 // over, pad w/ zeros.
1158                 //
1159
1160                 private static string FormatDecimal (byte value, int precision) 
1161                 {
1162                         return FormatDecimal ((uint)value, precision);
1163                 }
1164
1165                 private static string FormatDecimal (short value, int precision) 
1166                 {
1167                         return FormatDecimal ((int)value, precision);
1168                 }
1169         
1170                 private static string FormatDecimal (int value, int precision)
1171                 {
1172                         int size = (precision > 0) ? (maxIntLength + precision) : maxIntLength;
1173                         char[] buffy = new char[size];
1174                         int position = size;
1175                         bool negative = (value < 0);
1176                         
1177                         if (negative) 
1178                                 if (value <= -10) {
1179                                         buffy[--position] = digitLowerTable[-(value % 10)];
1180                                         value = value / -10;
1181                                 } else value = -value;
1182                         
1183                         // get our value into a buffer from right to left
1184                         while (value >= 10) {
1185                                 buffy[--position] = digitLowerTable[(value % 10)];
1186                                 value /= 10;
1187                         }
1188                                 
1189                         buffy[--position] = digitLowerTable[value];
1190
1191                         // if we have precision left over, fill with 0's
1192                         precision -= (size - position); 
1193                         while (precision-- > 0 && position > 1) 
1194                                 buffy[--position] = '0';
1195
1196                         if (negative) 
1197                                 buffy[--position] = '-';
1198                         
1199                         return new string (buffy, position, (size - position));  
1200                 }
1201
1202                 private static string FormatDecimal (long value, int precision)
1203                 {
1204                         int size = (precision > 0) ? (maxLongLength + precision) : maxLongLength;
1205                         char[] buffy = new char[size];
1206                         int position = size;
1207                         bool negative = (value < 0);
1208
1209                         if (negative) 
1210                                 if (value <= -10) {
1211                                         buffy[--position] = digitLowerTable[-(value % 10)];
1212                                         value = value / -10;
1213                                 } else value = -value;
1214
1215                         // get our value into a buffer from right to left
1216                         while (value >= 10) {
1217                                 buffy[--position] = digitLowerTable[(value % 10)];
1218                                 value /= 10;
1219                         }
1220                                 
1221                         buffy[--position] = digitLowerTable[value];
1222                         
1223                         // if we have precision left over, fill with 0's
1224                         precision -= (size - position); 
1225                         while (precision-- > 0 && position > 1)
1226                                 buffy[--position] = '0';
1227
1228                         if (negative) 
1229                                 buffy[--position] = '-';
1230                         
1231                         return new string (buffy, position, (size - position));  
1232                 }
1233
1234                 private static string FormatDecimal (sbyte value, int precision) 
1235                 {
1236                         return FormatDecimal ((int)value, precision);
1237                 }
1238
1239                 private static string FormatDecimal (ushort value, int precision) 
1240                 {
1241                         return FormatDecimal ((uint)value, precision);
1242                 }
1243
1244                 private static string FormatDecimal (uint value, int precision)
1245                 {
1246                         int size = (precision > 0) ? (maxIntLength + precision) : maxIntLength;
1247                         char[] buffy = new char[size];
1248                         int position = size;
1249
1250                         // get our value into a buffer from right to left
1251                         while (value >= 10) {
1252                                 buffy[--position] = digitLowerTable[(value % 10)];
1253                                 value /= 10;
1254                         }
1255                                 
1256                         buffy[--position] = digitLowerTable[value];
1257                         
1258                         // if we have precision left over, fill with 0's
1259                         precision -= (size - position); 
1260                         while (precision-- > 0 && position > 1) 
1261                                 buffy[--position] = '0';
1262
1263                         return new string (buffy, position, (size - position));  
1264                 }
1265
1266                 private static string FormatDecimal (ulong value, int precision)
1267                 {
1268                         int size = (precision > 0) ? (maxLongLength + precision) : maxLongLength;
1269                         char[] buffy = new char[size];
1270                         int position = size;
1271
1272                         // get our value into a buffer from right to left
1273                         while (value >= 10) {
1274                                 buffy[--position] = digitLowerTable[(value % 10)];
1275                                 value /= 10;
1276                         }
1277                                 
1278                         buffy[--position] = digitLowerTable[value];
1279                         
1280                         // if we have precision left over, fill with 0's
1281                         precision -= (size - position); 
1282                         while (precision-- > 0 && position > 1)
1283                                 buffy[--position] = '0';
1284
1285                         return new string (buffy, position, (size - position));  
1286                 }
1287
1288                 // ============ Format Exponentials ============ //
1289
1290                 //
1291                 // Used for strings in the format [-]M.DDDDDDe+XXX.
1292                 // Exaclty one non-zero digit must appear in M, w/ 
1293                 // a '-' sign if negative. The precision determines 
1294                 // number of decimal places, if not given go 6 places.
1295                 // If precision > the number of places we need, it
1296                 // is right padded w/ 0's. If it is smaller than what
1297                 // we need, we cut off and round. The format specifier
1298                 // decides whether we use an uppercase E or lowercase e.
1299                 // 
1300                 // Tried to do this in one pass of one buffer, but it
1301                 // wasn't happening. Get a buffer + 7 extra slots for
1302                 // the -, ., E, +, and XXX. Parse the value into another
1303                 // temp buffer, then build the new string. For the
1304                 // integral data types, there are a couple things that
1305                 // can be hardcoded. Since an int and a long can't be
1306                 // larger than 20 something spaces, the first X w/ 
1307                 // always be 0, and the the exponential value will only
1308                 // be 2 digits long. Also integer types w/ always
1309                 // have a positive exponential.
1310                 //
1311                 
1312                 private static string FormatExponential (byte value, int precision, bool upper) 
1313                 {
1314                         return FormatExponential ((uint)value, precision, upper);
1315                 }
1316
1317                 private static string FormatExponential (short value, int precision, bool upper) 
1318                 {
1319                         return FormatExponential ((int)value, precision, upper);
1320                 }
1321
1322                 private static string FormatExponential (int value, int precision, bool upper)
1323                 {
1324                         bool negative = (value < 0);
1325                         int padding = (precision >= 0) ? precision : 6;
1326                         char[] buffy = new char[(padding + 8)];
1327                         char[] tmp = new char [maxIntLength];
1328                         int exponent = 0, position = maxIntLength;
1329                         int exp = 0, idx = 0;
1330                         ulong pow = 10;
1331
1332                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1333                         uint number = (negative) ? (uint)((-(value + 1)) + 1) : (uint)value;
1334
1335                         // need to calculate the number of places to know if we need to round later
1336                         if (negative && value <= -10) {
1337                                 value /= -10;
1338                                 exp++;
1339                         }
1340
1341                         while (value >= 10) {
1342                                 value /= 10;
1343                                 exp++;
1344                         }
1345                                                         
1346                         if (exp > padding) {
1347
1348                                 // highest number we should goto before we round
1349                                 while (idx++ <= padding)
1350                                         pow *= 10;
1351
1352                                 // get our value into a buffer
1353                                 while (number > pow) {
1354                                         tmp[--position] = digitLowerTable[(number % 10)];
1355                                         number /= 10;
1356                                         exponent++;
1357                                 }
1358                         
1359                                 number += 5;
1360                         }
1361
1362                         while (number >= 10) {
1363                                 tmp[--position] = digitLowerTable[(number% 10)];
1364                                 number /= 10;
1365                                 exponent++;
1366                         }                      
1367
1368                         tmp[--position] = digitLowerTable[number];
1369                         idx = 0;
1370                         
1371                         // go left to right in filling up new string
1372                         if (negative)
1373                                 buffy[idx++] = '-';
1374
1375                         // we know we have at least one in there, followed 
1376                         // by a decimal point
1377                         buffy[idx++] = tmp[position++];
1378                         if (precision != 0)
1379                                 buffy[idx++] = '.';
1380
1381                         // copy over the remaining digits until we run out,
1382                         // or we've passed our specified precision
1383                         while (padding > 0 && position < maxIntLength) {
1384                                 buffy[idx++] = tmp[position++];
1385                                 padding--;
1386                         }
1387                         
1388                         // if we still have more precision to go, add some
1389                         // zeros
1390                         while (padding > 0) {
1391                                 buffy[idx++] = '0';
1392                                 padding--;
1393                         }
1394                         
1395                         // we know these next 3 spots
1396                         buffy[idx++] = upper ? 'E' : 'e';
1397                         buffy[idx++] = '+';
1398                         buffy[idx++] = '0';
1399                         
1400                         // next two digits depend on our length
1401                         if (exponent >= 10) {
1402                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1403                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1404                         } else { 
1405                                 buffy[idx++] = '0';
1406                                 buffy[idx] = digitLowerTable[exponent];
1407                         }
1408
1409                         return new string(buffy, 0, ++idx); 
1410                 }
1411
1412                 private static string FormatExponential (long value, int precision, bool upper)
1413                 {
1414                         bool negative = (value < 0);
1415                         int padding = (precision >= 0) ? precision : 6;
1416                         char[] buffy = new char[(padding + 8)];
1417                         char[] tmp = new char [maxLongLength];
1418                         int exponent = 0, position = maxLongLength;
1419                         int exp = 0, idx = 0;
1420                         ulong pow = 10;
1421
1422                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1423                         ulong number = (negative) ? (ulong)((-(value + 1)) + 1) : (ulong)value;
1424
1425                         // need to calculate the number of places to know if we need to round later
1426                         if (negative && value <= -10) {
1427                                 value /= -10;
1428                                 exp++;
1429                         }
1430
1431                         while (value >= 10) {
1432                                 value /= 10;
1433                                 exp++;
1434                         }
1435                                                         
1436                         if (exp > padding) {
1437                                 
1438                                 // highest number we should goto before we round
1439                                 while (idx++ <= padding)
1440                                         pow *= 10;
1441                                 
1442                                 // get our value into a buffer
1443                                 while (number > pow) {
1444                                         tmp[--position] = digitLowerTable[(number % 10)];
1445                                         number /= 10;
1446                                         exponent++;
1447                                 }
1448                         
1449                                 number += 5;
1450                         }
1451
1452                         while (number >= 10) {
1453                                 tmp[--position] = digitLowerTable[(number% 10)];
1454                                 number /= 10;
1455                                 exponent++;
1456                         }                      
1457
1458                         tmp[--position] = digitLowerTable[number];
1459                         idx = 0;
1460
1461                         // go left to right in filling up new string
1462                         if (negative)
1463                                 buffy[idx++] = '-';
1464
1465                         // we know we have at least one in there, followed 
1466                         // by a decimal point
1467                         buffy[idx++] = tmp[position++];
1468                         if (precision != 0)
1469                                 buffy[idx++] = '.';
1470
1471                         // copy over the remaining digits until we run out,
1472                         // or we've passed our specified precision
1473                         while (padding > 0 && position < maxLongLength) {
1474                                 buffy[idx++] = tmp[position++];
1475                                 padding--;
1476                         }
1477                         
1478                         // if we still have more precision to go, add some
1479                         // zeros
1480                         while (padding > 0) {
1481                                 buffy[idx++] = '0';
1482                                 padding--;
1483                         }
1484                         
1485                         // we know these next 3 spots
1486                         buffy[idx++] = upper ? 'E' : 'e';
1487                         buffy[idx++] = '+';
1488                         buffy[idx++] = '0';
1489                         
1490                         // next two digits depend on our length
1491                         if (exponent >= 10) {
1492                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1493                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1494                         } else { 
1495                                 buffy[idx++] = '0';
1496                                 buffy[idx] = digitLowerTable[exponent];
1497                         }
1498
1499                         return new string(buffy, 0, ++idx); 
1500                 }
1501
1502                 private static string FormatExponential (sbyte value, int precision, bool upper) 
1503                 {
1504                         return FormatExponential ((int)value, precision, upper);
1505                 }
1506
1507                 private static string FormatExponential (ushort value, int precision, bool upper) 
1508                 {
1509                         return FormatExponential ((uint)value, precision, upper);
1510                 }
1511
1512                 private static string FormatExponential (uint value, int precision, bool upper)
1513                 {
1514                         int padding = (precision >= 0) ? precision : 6;
1515                         char[] buffy = new char[(padding + 8)];
1516                         char[] tmp = new char [maxIntLength];
1517                         int exponent = 0, position = maxIntLength;
1518                         int exp = 0, idx = 0;
1519                         ulong pow = 10;
1520                         uint number = value;
1521
1522                         // need to calculate the number of places to know if we need to round later
1523                         while (value >= 10) {
1524                                 value /= 10;
1525                                 exp++;
1526                         }
1527                                                         
1528                         if (exp > padding) {
1529
1530                                 // highest number we should goto before we round
1531                                 while (idx++ <= padding)
1532                                         pow *= 10;
1533                                 
1534                                 // get our value into a buffer
1535                                 while (number > pow) {
1536                                         tmp[--position] = digitLowerTable[(number % 10)];
1537                                         number /= 10;
1538                                         exponent++;
1539                                 }
1540                                 
1541                                 number += 5;
1542                         }
1543
1544                         while (number >= 10) {
1545                                 tmp[--position] = digitLowerTable[(number% 10)];
1546                                 number /= 10;
1547                                 exponent++;
1548                         }                      
1549
1550                         tmp[--position] = digitLowerTable[number];
1551                         idx = 0;
1552
1553                         // we know we have at least one in there, followed 
1554                         // by a decimal point
1555                         buffy[idx++] = tmp[position++];
1556                         if (precision != 0)
1557                                 buffy[idx++] = '.';
1558
1559                         // copy over the remaining digits until we run out,
1560                         // or we've passed our specified precision
1561                         while (padding > 0 && position < maxIntLength) {
1562                                 buffy[idx++] = tmp[position++];
1563                                 padding--;
1564                         }
1565                         
1566                         // if we still have more precision to go, add some
1567                         // zeros
1568                         while (padding > 0) {
1569                                 buffy[idx++] = '0';
1570                                 padding--;
1571                         }
1572                         
1573                         // we know these next 3 spots
1574                         buffy[idx++] = upper ? 'E' : 'e';
1575                         buffy[idx++] = '+';
1576                         buffy[idx++] = '0';
1577                         
1578                         // next two digits depend on our length
1579                         if (exponent >= 10) {
1580                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1581                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1582                         } else { 
1583                                 buffy[idx++] = '0';
1584                                 buffy[idx] = digitLowerTable[exponent];
1585                         }
1586
1587                         return new string(buffy, 0, ++idx); 
1588                 }
1589
1590                 private static string FormatExponential (ulong value, int precision, bool upper)
1591                 {
1592                         int padding = (precision >= 0) ? precision : 6;
1593                         char[] buffy = new char[(padding + 8)];
1594                         char[] tmp = new char [maxLongLength];
1595                         int exponent = 0, position = maxLongLength;
1596                         int exp = 0, idx = 0;
1597                         ulong pow = 10;
1598                         ulong number = value;
1599
1600                         // need to calculate the number of places to know if we need to round later
1601                         while (value >= 10) {
1602                                 value /= 10;
1603                                 exp++;
1604                         }
1605                                                         
1606                         if (exp > padding) {
1607
1608                                 // highest number we should goto before we round
1609                                 while (idx++ <= padding)
1610                                         pow *= 10;
1611
1612                                 // get our value into a buffer
1613                                 while (number > pow) {
1614                                         tmp[--position] = digitLowerTable[(number % 10)];
1615                                         number /= 10;
1616                                         exponent++;
1617                                 }
1618                         
1619                                 number += 5;
1620                         }
1621
1622                         while (number >= 10) {
1623                                 tmp[--position] = digitLowerTable[(number% 10)];
1624                                 number /= 10;
1625                                 exponent++;
1626                         }                      
1627
1628                         tmp[--position] = digitLowerTable[number];
1629                         idx = 0;
1630
1631                         // we know we have at least one in there, followed 
1632                         // by a decimal point
1633                         buffy[idx++] = tmp[position++];
1634                         if (precision != 0)
1635                                 buffy[idx++] = '.';
1636
1637                         // copy over the remaining digits until we run out,
1638                         // or we've passed our specified precision
1639                         while (padding > 0 && position < maxLongLength) {
1640                                 buffy[idx++] = tmp[position++];
1641                                 padding--;
1642                         }
1643                         
1644                         // if we still have more precision to go, add some
1645                         // zeros
1646                         while (padding > 0) {
1647                                 buffy[idx++] = '0';
1648                                 padding--;
1649                         }
1650                         
1651                         // we know these next 3 spots
1652                         buffy[idx++] = upper ? 'E' : 'e';
1653                         buffy[idx++] = '+';
1654                         buffy[idx++] = '0';
1655                         
1656                         // next two digits depend on our length
1657                         if (exponent >= 10) {
1658                                 buffy[idx++] = digitLowerTable[(exponent / 10)];
1659                                 buffy[idx] = digitLowerTable[(exponent % 10)];
1660                         } else { 
1661                                 buffy[idx++] = '0';
1662                                 buffy[idx] = digitLowerTable[exponent];
1663                         }
1664
1665                         return new string(buffy, 0, ++idx); 
1666                 }
1667
1668                 // ============ Format Fixed Points ============ //
1669
1670                 //
1671                 // Used for strings in the following form "[-]M.DD...D"
1672                 // At least one non-zero digit precedes the '.', w/ a 
1673                 // '-' before that if negative. Precision specifies number
1674                 // of decimal places 'D' to go. If not given, use
1675                 // NumberFormatInfo.NumbeDecimalDigits. Results are rounded
1676                 // if necessary. 
1677                 //
1678                 // Fairly simple implementation for integral types. Going
1679                 // from right to left, fill up precision number of 0's,
1680                 // plop a . down, then go for our number. 
1681                 //
1682
1683                 private static string FormatFixedPoint (byte value, int precision, NumberFormatInfo nfi)
1684                 {
1685                         return FormatFixedPoint ((uint)value, precision, nfi);
1686                 }
1687
1688                 private static string FormatFixedPoint (short value, int precision, NumberFormatInfo nfi)
1689                 {
1690                         return FormatFixedPoint ((int)value, precision, nfi);
1691                 }
1692
1693                 private static string FormatFixedPoint (int value, int precision, NumberFormatInfo nfi)
1694                 {
1695                         int padding = (precision >= 0) ? (precision + maxIntLength) : (nfi.NumberDecimalDigits + maxIntLength);
1696                         char[] buffy = new char[padding];
1697                         int position = padding;
1698                         bool negative = (value < 0);
1699                         
1700                         // fill up w/ precision # of 0's
1701                         while (position > (maxIntLength - 1)) 
1702                                 buffy[--position] = '0';
1703
1704                         if (precision != 0)
1705                                 buffy[position--] = '.';
1706
1707                         if (negative)
1708                                 if (value <= -10) {
1709                                         buffy[position--] = digitLowerTable[-(value % 10)];
1710                                         value = value / -10;
1711                                 } else value = -value;
1712                         
1713                         // fill up w/ the value
1714                         while (value >= 10) {
1715                                 buffy[position--] = digitLowerTable[(value % 10)];
1716                                 value = value / 10;
1717                         }
1718
1719                         buffy[position] = digitLowerTable[value];
1720
1721                         if (negative) 
1722                                 buffy[--position] = '-';
1723                         
1724                         return new string (buffy, position, (padding - position));
1725                 }
1726
1727                 private static string FormatFixedPoint (long value, int precision, NumberFormatInfo nfi)
1728                 {
1729                         int padding = (precision >= 0) ? (precision + maxLongLength) : (nfi.NumberDecimalDigits + maxLongLength);
1730                         char[] buffy = new char[padding];
1731                         int position = padding;
1732                         bool negative = (value < 0);
1733                         
1734                         // fill up w/ precision # of 0's
1735                         while (position > (maxLongLength - 1)) 
1736                                 buffy[--position] = '0';
1737
1738                         if (precision != 0)
1739                                 buffy[position--] = '.';
1740
1741                         if (negative)
1742                                 if (value <= -10) {
1743                                         buffy[position--] = digitLowerTable[-(value % 10)];
1744                                         value = value / -10;
1745                                 } else value = -value;
1746                         
1747                         // fill up w/ the value
1748                         while (value >= 10) {
1749                                 buffy[position--] = digitLowerTable[(value % 10)];
1750                                 value = value / 10;
1751                         }
1752
1753                         buffy[position] = digitLowerTable[value];
1754
1755                         if (negative) 
1756                                 buffy[--position] = '-';
1757                         
1758                         return new string (buffy, position, (padding - position));
1759                 }
1760
1761                 private static string FormatFixedPoint (sbyte value, int precision, NumberFormatInfo nfi)
1762                 {
1763                         return FormatFixedPoint ((int)value, precision, nfi);
1764                 }
1765
1766                 private static string FormatFixedPoint (ushort value, int precision, NumberFormatInfo nfi)
1767                 {
1768                         return FormatFixedPoint ((uint)value, precision, nfi);
1769                 }
1770
1771                 private static string FormatFixedPoint (uint value, int precision, NumberFormatInfo nfi)
1772                 {
1773                         int padding = (precision >= 0) ? (precision + maxIntLength) : (nfi.NumberDecimalDigits + maxIntLength);
1774                         char[] buffy = new char[padding];
1775                         int position = padding;
1776
1777                         // fill up w/ precision # of 0's
1778                         while (position > (maxIntLength - 1)) 
1779                                 buffy[--position] = '0';
1780
1781                         if (precision != 0)
1782                                 buffy[position--] = '.';
1783
1784                         // fill up w/ the value
1785                         while (value >= 10) {
1786                                 buffy[position--] = digitLowerTable[(value % 10)];
1787                                 value = value / 10;
1788                         }
1789
1790                         buffy[position] = digitLowerTable[value];
1791                         
1792                         return new string (buffy, position, (padding - position));
1793                 }
1794
1795                 private static string FormatFixedPoint (ulong value, int precision, NumberFormatInfo nfi)
1796                 {
1797                         int padding = (precision >= 0) ? (precision + maxLongLength) : (nfi.NumberDecimalDigits + maxLongLength);
1798                         char[] buffy = new char[padding];
1799                         int position = padding;
1800
1801                         // fill up w/ precision # of 0's
1802                         while (position > (maxLongLength - 1)) 
1803                                 buffy[--position] = '0';
1804
1805                         if (precision != 0)
1806                                 buffy[position--] = '.';
1807
1808                         // fill up w/ the value
1809                         while (value >= 10) {
1810                                 buffy[position--] = digitLowerTable[(value % 10)];
1811                                 value = value / 10;
1812                         }
1813
1814                         buffy[position] = digitLowerTable[value];
1815                         
1816                         return new string (buffy, position, (padding - position));
1817                 }
1818
1819                 // ============ Format General ============ //
1820                 
1821                 //
1822                 // Strings are formatted in either Fixed Point or Exponential
1823                 // format. Results are rounded when needed. If no precision is
1824                 // given, the defaults are:
1825                 //
1826                 // short & ushort: 5
1827                 // int & uint: 10
1828                 // long & ulong: 19
1829                 // float: 7
1830                 // double: 15
1831                 // decimal: 29
1832                 //
1833                 // The value is formatted using fixed-point if exponent >= -4
1834                 // and exponent < precision, where exponent is he exponenent of
1835                 // the value in exponential format. The decimal point and trailing
1836                 // zeros are removed when possible.
1837                 //
1838                 // For all other values, exponential format is used. The case of
1839                 // the format specifier determines whether 'e' or 'E' prefixes
1840                 // the exponent.
1841                 // 
1842                 // In either case, the number of digits that appear in the result
1843                 // (not including the exponent) will not exceed the value of the
1844                 // precision. The result is rounded as needed.
1845                 //
1846                 // Integral values are formatted using Fixed Point whenever
1847                 // precision is omitted. (This actually doesn't make sense when
1848                 // coupled w/ the 1st paragraph).
1849                 //              
1850                 // Okay, so the decimal point is removed along with any trailing
1851                 // zeros. So, ignoring the last paragraph, we can consider an int
1852                 // ToString() to format it w/ exponential format w/ a default
1853                 // precision of 10, but since it will just be .00000000, it's
1854                 // discarded.
1855                 //
1856
1857                 private static string FormatGeneral (byte value, int precision, NumberFormatInfo nfi, bool upper) {
1858                         return FormatGeneral ((uint)value, precision, nfi, upper);
1859                 }
1860
1861                 private static string FormatGeneral (short value, int precision, NumberFormatInfo nfi, bool upper) {
1862                         return FormatGeneral ((int)value, precision, nfi, upper);
1863                 }
1864
1865                 private static string FormatGeneral (int value, int precision, NumberFormatInfo nfi, bool upper) 
1866                 {
1867                         bool negative = (value < 0);
1868                         char[] tmp = new char [maxIntLength];
1869                         int exponent = 0;
1870                         int position = maxIntLength;
1871                         
1872                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1873                         uint number = (negative) ? (uint)((-(value + 1)) + 1) : (uint)value;
1874
1875                         // get number into a buffer, going to be doing this no matter what
1876                         if (negative)
1877                                 if (value <= -10) {
1878                                         tmp[--position] = digitLowerTable[-(value % 10)];
1879                                         value /= -10;
1880                                         exponent++;
1881                                 } else value = -value;
1882
1883                         while (value >= 10) {
1884                                 tmp[--position] = digitLowerTable[(value % 10)];
1885                                 value /= 10;
1886                                 exponent++;
1887                         }
1888                         
1889                         tmp[--position] = digitLowerTable[value];
1890
1891                         // integral values are formatted using fixed point when precision
1892                         // is not specified. But also trailing decimal point and zeros are
1893                         // discared. So for int's it will always be .00, so just compute
1894                         // here and save the call to FormatFixedPoint & trim.
1895                         if (precision <= 0 || exponent < precision) {
1896                                 if (negative) 
1897                                         tmp[--position] = '-';
1898                                 
1899                                 return new string (tmp, position, (maxIntLength - position)); 
1900                         }
1901
1902                         // else our exponent was > precision, use exponential format
1903                         // precision = number of digits to show. 
1904                         int idx = 0, pow = 1;
1905
1906                         exponent = 0;
1907                         position = maxIntLength;
1908                         
1909                         // Loop through while our number is less than the 10 ^ precision, then
1910                         // add 5 to that to round it out, and keep continuing
1911                         while (idx++ <= precision)
1912                                 pow *= 10;
1913                         
1914                         while (number > pow) {
1915                                 tmp[--position] = digitLowerTable[(number % 10)];
1916                                 number /= 10;
1917                                 exponent++;
1918                         }
1919
1920                         number += 5;
1921
1922                         while (number >= 10) {
1923                                 tmp[--position] = digitLowerTable[(number % 10)];
1924                                 number /= 10;
1925                                 exponent++;
1926                         }
1927
1928                         tmp[--position] = digitLowerTable[number];
1929
1930                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
1931                         // and reuse pow for size
1932                         idx = position;
1933                         position = 0;
1934                         pow = precision + 6;
1935                         char[] buffy = new char[pow];
1936
1937                         if (negative)
1938                                 buffy[position++] = '-';
1939                         
1940                         buffy[position++] = tmp[idx++];
1941                         buffy[position] = '.';
1942
1943                         // for the remaining precisions copy over rounded tmp
1944                         precision--;
1945                         while (precision-- > 0)
1946                                 buffy[++position] = tmp[idx++];
1947
1948                         // get rid of ending zeros
1949                         while (buffy[position] == '0')
1950                                 position--;
1951
1952                         // if we backed up all the way to the ., over write it
1953                         if (buffy[position] != '.')
1954                                 position++;                     
1955
1956                         // ints can only be +, e or E depending on format, plus XX
1957                         buffy[position++] = upper ? 'E' : 'e';
1958                         buffy[position++] = '+';
1959
1960                         if (exponent >= 10) {
1961                                 buffy[position++] = digitLowerTable[(exponent / 10)];
1962                                 buffy[position++] = digitLowerTable[(exponent % 10)];
1963                         } else { 
1964                                 buffy[position++] = '0';
1965                                 buffy[position++] = digitLowerTable[exponent];
1966                         }
1967                         
1968                         return new string (buffy, 0, position);
1969                 }
1970
1971                 private static string FormatGeneral (long value, int precision, NumberFormatInfo nfi, bool upper) 
1972                 {
1973                         bool negative = (value < 0);
1974                         char[] tmp = new char [maxLongLength];
1975                         int exponent = 0;
1976                         int position = maxLongLength;
1977
1978                         // ugly, but doing it since abs(Int32.MinValue) > Int.MaxValue
1979                         ulong number = (negative) ? (ulong)(-(value + 1) + 1) : (ulong)value;
1980
1981                         // get number into a buffer, going to be doing this no matter what
1982                         if (negative)
1983                                 if (value <= -10) {
1984                                         tmp[--position] = digitLowerTable[-(value % 10)];
1985                                         value /= -10;
1986                                 } else value = -value;
1987
1988                         while (value >= 10) {
1989                                 tmp[--position] = digitLowerTable[(value % 10)];
1990                                 value /= 10;
1991                         }
1992                         
1993                         tmp[--position] = digitLowerTable[value];
1994                         exponent = (maxLongLength - position) - 1;
1995
1996                         // integral values are formatted using fixed point when precision
1997                         // is not specified. But also trailing decimal point and zeros are
1998                         // discared. So for int's it will always be .00, so just compute
1999                         // here and save the call to FormatFixedPoint & trim.
2000                         if (precision <= 0 || exponent < precision) {
2001                                 if (negative) 
2002                                         tmp[--position] = '-';
2003                                 
2004                                 return new string (tmp, position, (maxLongLength - position)); 
2005                         }
2006
2007                         // else our exponent was > precision, use exponential format
2008                         // precision = number of digits to show. 
2009                         int idx = 0;
2010                         ulong pow = 1;
2011
2012                         exponent = 0;
2013                         position = maxLongLength;
2014
2015                         // Loop through while our number is less than the 10 ^ precision, then
2016                         // add 5 to that to round it out, and keep continuing
2017                         while (idx++ <= precision)
2018                                 pow *= 10;
2019                         
2020                         while (number > pow) {
2021                                 tmp[--position] = digitLowerTable[(number % 10)];
2022                                 number /= 10;
2023                                 exponent++;
2024                         }
2025
2026                         number += 5;
2027
2028                         while (number >= 10) {
2029                                 tmp[--position] = digitLowerTable[(number % 10)];
2030                                 number /= 10;
2031                                 exponent++;
2032                         }
2033
2034                         tmp[--position] = digitLowerTable[number];
2035
2036                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2037                         // and reuse pow for size
2038                         idx = position;
2039                         position = 0;
2040                         pow = (ulong)precision + 6;
2041                         char[] buffy = new char[pow];
2042
2043                         if (negative)
2044                                 buffy[position++] = '-';
2045                         
2046                         buffy[position++] = tmp[idx++];
2047                         buffy[position] = '.';
2048
2049                         // for the remaining precisions copy over rounded tmp
2050                         precision--;
2051                         while (precision-- > 0)
2052                                 buffy[++position] = tmp[idx++];
2053
2054                         // get rid of ending zeros
2055                         while (buffy[position] == '0')
2056                                 position--;
2057
2058                         // if we backed up all the way to the ., over write it
2059                         if (buffy[position] != '.')
2060                                 position++;                     
2061
2062                         // ints can only be +, e or E depending on format, plus XX
2063                         buffy[position++] = upper ? 'E' : 'e';
2064                         buffy[position++] = '+';
2065
2066                         if (exponent >= 10) {
2067                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2068                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2069                         } else { 
2070                                 buffy[position++] = '0';
2071                                 buffy[position++] = digitLowerTable[exponent];
2072                         }
2073                         
2074                         return new string (buffy, 0, position);
2075                 }
2076
2077                 private static string FormatGeneral (sbyte value, int precision, NumberFormatInfo nfi, bool upper) {
2078                         return FormatGeneral ((int)value, precision, nfi, upper);
2079                 }
2080
2081                 private static string FormatGeneral (ushort value, int precision, NumberFormatInfo nfi, bool upper) {
2082                         return FormatGeneral ((uint)value, precision, nfi, upper);
2083                 }
2084
2085                 private static string FormatGeneral (uint value, int precision, NumberFormatInfo nfi, bool upper) 
2086                 {
2087                         char[] tmp = new char [maxIntLength];
2088                         int exponent = 0;
2089                         int position = maxIntLength;
2090                         uint number = value;
2091
2092                         // get number into a buffer, going to be doing this no matter what
2093                         while (value >= 10) {
2094                                 tmp[--position] = digitLowerTable[(value % 10)];
2095                                 value /= 10;
2096                         }
2097                         
2098                         tmp[--position] = digitLowerTable[value];
2099                         exponent = (maxIntLength - position) - 1;
2100
2101                         // integral values are formatted using fixed point when precision
2102                         // is not specified. But also trailing decimal point and zeros are
2103                         // discared. So for int's it will always be .00, so just compute
2104                         // here and save the call to FormatFixedPoint & trim.
2105                         if (precision <= 0 || exponent < precision) 
2106                                 return new string (tmp, position, (maxIntLength - position)); 
2107
2108                         // else our exponent was > precision, use exponential format
2109                         // precision = number of digits to show. 
2110                         int idx = 0, pow = 1;
2111
2112                         exponent = 0;
2113                         position = maxIntLength;
2114                                                 
2115                         // Loop through while our number is less than the 10 ^ precision, then
2116                         // add 5 to that to round it out, and keep continuing
2117                         while (idx++ <= precision)
2118                                 pow *= 10;
2119
2120                         while (number > pow) {
2121                                 tmp[--position] = digitLowerTable[(number % 10)];
2122                                 number /= 10;
2123                                 exponent++;
2124                         }
2125
2126                         number += 5;
2127
2128                         while (number >= 10) {
2129                                 tmp[--position] = digitLowerTable[(number % 10)];
2130                                 number /= 10;
2131                                 exponent++;
2132                         }
2133
2134                         tmp[--position] = digitLowerTable[number];      
2135
2136                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2137                         // and reuse pow for size
2138                         idx = position;
2139                         position = 0;
2140                         pow = precision + 6;
2141                         char[] buffy = new char[pow];
2142
2143                         buffy[position++] = tmp[idx++];
2144                         buffy[position] = '.';
2145
2146                         // for the remaining precisions copy over rounded tmp
2147                         precision--;
2148                         while (precision-- > 0)
2149                                 buffy[++position] = tmp[idx++];
2150
2151                         // get rid of ending zeros
2152                         while (buffy[position] == '0')
2153                                 position--;
2154
2155                         // if we backed up all the way to the ., over write it
2156                         if (buffy[position] != '.')
2157                                 position++;                     
2158
2159                         // ints can only be +, e or E depending on format, plus XX
2160                         buffy[position++] = upper ? 'E' : 'e';
2161                         buffy[position++] = '+';
2162
2163                         if (exponent >= 10) {
2164                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2165                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2166                         } else { 
2167                                 buffy[position++] = '0';
2168                                 buffy[position++] = digitLowerTable[exponent];
2169                         }
2170                         
2171                         return new string (buffy, 0, position);
2172                 }
2173
2174                 private static string FormatGeneral (ulong value, int precision, NumberFormatInfo nfi, bool upper) 
2175                 {
2176                         char[] tmp = new char [maxLongLength];
2177                         int exponent = 0;
2178                         int position = maxLongLength;
2179                         ulong number = value;
2180
2181                         // get number into a buffer, going to be doing this no matter what
2182                         while (value >= 10) {
2183                                 tmp[--position] = digitLowerTable[(value % 10)];
2184                                 value /= 10;
2185                                 exponent++;
2186                         }
2187                         
2188                         tmp[--position] = digitLowerTable[value];
2189
2190                         // integral values are formatted using fixed point when precision
2191                         // is not specified. But also trailing decimal point and zeros are
2192                         // discared. So for int's it will always be .00, so just compute
2193                         // here and save the call to FormatFixedPoint & trim.
2194                         if (precision <= 0 || exponent < precision) 
2195                                 return new string (tmp, position, (maxLongLength - position)); 
2196
2197                         // else our exponent was > precision, use exponential format
2198                         // precision = number of digits to show. 
2199                         int idx = 0;
2200                         ulong pow = 1;
2201
2202                         exponent = 0;
2203                         position = maxLongLength;
2204
2205                         // Loop through while our number is less than the 10 ^ precision, then
2206                         // add 5 to that to round it out, and keep continuing
2207                         while (idx++ <= precision)
2208                                 pow *= 10;
2209                         
2210                         while (number > pow) {
2211                                 tmp[--position] = digitLowerTable[(number % 10)];
2212                                 number /= 10;
2213                                 exponent++;
2214                         }
2215
2216                         number += 5;
2217
2218                         while (number >= 10) {
2219                                 tmp[--position] = digitLowerTable[(number % 10)];
2220                                 number /= 10;
2221                                 exponent++;
2222                         }
2223
2224                         tmp[--position] = digitLowerTable[number];
2225
2226                         // finally, make our final buffer, at least precision + 6 for 'E+XX' and '-'
2227                         // and reuse pow for size
2228                         idx = position;
2229                         position = 0;
2230                         pow = (ulong)precision + 6;
2231                         char[] buffy = new char[pow];
2232
2233                         buffy[position++] = tmp[idx++];
2234                         buffy[position] = '.';
2235
2236                         // for the remaining precisions copy over rounded tmp
2237                         precision--;
2238                         while (precision-- > 0)
2239                                 buffy[++position] = tmp[idx++];
2240
2241                         // get rid of ending zeros
2242                         while (buffy[position] == '0')
2243                                 position--;
2244
2245                         // if we backed up all the way to the ., over write it
2246                         if (buffy[position] != '.')
2247                                 position++;                     
2248
2249                         // ints can only be +, e or E depending on format, plus XX
2250                         buffy[position++] = upper ? 'E' : 'e';
2251                         buffy[position++] = '+';
2252
2253                         if (exponent >= 10) {
2254                                 buffy[position++] = digitLowerTable[(exponent / 10)];
2255                                 buffy[position++] = digitLowerTable[(exponent % 10)];
2256                         } else { 
2257                                 buffy[position++] = '0';
2258                                 buffy[position++] = digitLowerTable[exponent];
2259                         }
2260                         
2261                         return new string (buffy, 0, position);
2262                 }
2263
2264                 // ============ Format Number ============ //
2265
2266                 // 
2267                 // Used for strings in the following form "[-]d,ddd,ddd.dd...d"
2268                 // The minus sign only appears if it is negative. At least one
2269                 // non-zero digit preceeds the decimal separator. The precision
2270                 // specifier determines the number of decimal places. If it is 
2271                 // not given, use NumberFormatInfo.NumberDecimalDigits.
2272                 // The NumberGroupSizes, NumberGroupSeparator, and NumberDecimalSeparator
2273                 // members of NumberFormatInfo supply the size and separator
2274                 // for digit groupings. See IFormattable.
2275                 //
2276                 // The group sizes is an array of ints that determine the grouping
2277                 // of numbers. All digits are in the range 1-9, with the last digit
2278                 // being between 0-9. The number formats the string backwards, with
2279                 // the last digit being the group size for the rest of (leftmost) the
2280                 // the string, 0 being none.
2281                 //
2282                 // For instance:
2283                 //              groupSizes = { 3, 2, 1, 0 }; 
2284                 //              int n = 1234567890 => "1234,5,67,890"
2285                 //              groupSizes = { 3, 2, 1 }; 
2286                 //              int n = 1234567890 => "1,2,3,4,5,67,890"
2287                 //              groupSizes = { 2, 0 };
2288                 //              int n = 1234567890 => "1234567,90";
2289                 //
2290                 // Not too difficult, jsut keep track of where you are in the array
2291                 // and when to print the separator
2292                 //
2293                 // The max size of the buffer is assume we have a separator every 
2294                 // number, plus the precision on the end, plus a spot for the negative
2295                 // and a spot for decimal separator.
2296                 //
2297
2298                 private static string FormatNumber (byte value, int precision, NumberFormatInfo nfi) {
2299                         return FormatNumber ((uint)value, precision, nfi);
2300                 }
2301
2302                 private static string FormatNumber (short value, int precision, NumberFormatInfo nfi) {
2303                         return FormatNumber ((int)value, precision, nfi);
2304                 }
2305
2306                 private static string FormatNumber (int value, int precision, NumberFormatInfo nfi) 
2307                 {
2308                         int i, j, k;
2309                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2310                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2311                         int[] groupSizes = nfi.NumberGroupSizes;
2312
2313                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2314                         int size = maxIntLength + (maxIntLength * groupSeparator.Length) + padding +
2315                         decimalSeparator.Length + 2;
2316                         char[] buffy = new char[size];
2317                         int position = size;
2318                         bool negative = (value < 0);
2319                         
2320                         // right pad it w/ precision 0's
2321                         while (padding-- > 0)
2322                                 buffy[--position] = '0';
2323
2324                         // put on decimal separator
2325                         if (position != size) {
2326                                 i = decimalSeparator.Length; 
2327                                 do {
2328                                         buffy[--position] = decimalSeparator[--i];
2329                                 } while (i > 0);                        
2330                         }
2331
2332                         // loop through, keeping track of where you are in the
2333                         // group sizes array and putting out the group separator
2334                         // when needed
2335                         j = 0;
2336                         k = groupSizes[j++];
2337
2338                         // negative hack for numbers past MinValue
2339                         if (negative)
2340                                 if (value <= -10) {
2341                                         buffy[--position] = digitLowerTable[-(value % 10)];
2342                                         value = value / -10;
2343                                         
2344                                         if (--k == 0) {
2345                                                 i = groupSeparator.Length; 
2346                                                 do {
2347                                                         buffy[--position] = groupSeparator[--i];
2348                                                 } while (i > 0);
2349                                                 
2350                                                 k = (j < groupSizes.Length) ? 
2351                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2352                                         }
2353                                 } else value = -value;
2354
2355                         while (value >= 10) {
2356                                 buffy[--position] = digitLowerTable[(value % 10)];
2357                                 value /= 10;
2358
2359                                 if (--k == 0) {
2360                                         i = groupSeparator.Length; 
2361                                         do {
2362                                                 buffy[--position] = groupSeparator[--i];
2363                                         } while (i > 0);
2364                                         
2365                                         k = (j < groupSizes.Length) ? 
2366                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2367                                 }
2368                         }                
2369
2370                         buffy[--position] = digitLowerTable[value];
2371
2372                         if (negative)
2373                                 buffy[--position] = '-';
2374                         
2375                         return new string (buffy, position, (size - position));
2376                 }
2377
2378                 private static string FormatNumber (long value, int precision, NumberFormatInfo nfi) 
2379                 {
2380                         int i, j, k;
2381                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2382                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2383                         int[] groupSizes = nfi.NumberGroupSizes;
2384
2385                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2386                         int size = maxLongLength + (maxLongLength * groupSeparator.Length) + padding +
2387                         decimalSeparator.Length + 2;
2388                         char[] buffy = new char[size];
2389                         int position = size;
2390                         bool negative = (value < 0);
2391                         
2392                         // right pad it w/ precision 0's
2393                         while (padding-- > 0)
2394                                 buffy[--position] = '0';
2395                                                 
2396                         // put on decimal separator
2397                         if (position != size) {
2398                                 i = decimalSeparator.Length; 
2399                                 do {
2400                                         buffy[--position] = decimalSeparator[--i];
2401                                 } while (i > 0);                        
2402                         }
2403
2404                         // loop through, keeping track of where you are in the
2405                         // group sizes array and putting out the group separator
2406                         // when needed
2407                         j = 0;
2408                         k = groupSizes[j++];
2409
2410                         // negative hack for numbers past MinValue
2411                         if (negative)
2412                                 if (value <= -10) {
2413                                         buffy[--position] = digitLowerTable[-(value % 10)];
2414                                         value = value / -10;
2415                                         
2416                                         if (--k == 0) {
2417                                                 i = groupSeparator.Length; 
2418                                                 do {
2419                                                         buffy[--position] = groupSeparator[--i];
2420                                                 } while (i > 0);
2421                                                 
2422                                                 k = (j < groupSizes.Length) ? 
2423                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2424                                         }
2425                                 } else value = -value;
2426
2427                         while (value >= 10) {
2428                                 buffy[--position] = digitLowerTable[(value % 10)];
2429                                 value /= 10;
2430
2431                                 if (--k == 0) {
2432                                         i = groupSeparator.Length; 
2433                                         do {
2434                                                 buffy[--position] = groupSeparator[--i];
2435                                         } while (i > 0);
2436                                         
2437                                         k = (j < groupSizes.Length) ? 
2438                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2439                                 }
2440                         }                
2441
2442                         buffy[--position] = digitLowerTable[value];
2443
2444                         if (negative)
2445                                 buffy[--position] = '-';
2446                         
2447                         return new string (buffy, position, (size - position));
2448                 }
2449
2450                 private static string FormatNumber (sbyte value, int precision, NumberFormatInfo nfi) {
2451                         return FormatNumber ((int)value, precision, nfi);
2452                 }
2453
2454                 private static string FormatNumber (ushort value, int precision, NumberFormatInfo nfi) {
2455                         return FormatNumber ((uint)value, precision, nfi);
2456                 }
2457
2458                 private static string FormatNumber (uint value, int precision, NumberFormatInfo nfi) 
2459                 {
2460                         int i, j, k;
2461                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2462                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2463                         int[] groupSizes = nfi.NumberGroupSizes;
2464
2465                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2466                         int size = maxIntLength + (maxIntLength * groupSeparator.Length) + padding +
2467                         decimalSeparator.Length + 2;
2468                         char[] buffy = new char[size];
2469                         int position = size;
2470                         
2471                         // right pad it w/ precision 0's
2472                         while (padding-- > 0)
2473                                 buffy[--position] = '0';
2474                                                 
2475                         // put on decimal separator
2476                         if (position != size) {
2477                                 i = decimalSeparator.Length; 
2478                                 do {
2479                                         buffy[--position] = decimalSeparator[--i];
2480                                 } while (i > 0);                        
2481                         }
2482
2483                         // loop through, keeping track of where you are in the
2484                         // group sizes array and putting out the group separator
2485                         // when needed
2486                         j = 0;
2487                         k = groupSizes[j++];
2488
2489                         while (value >= 10) {
2490                                 buffy[--position] = digitLowerTable[(value % 10)];
2491                                 value /= 10;
2492
2493                                 if (--k == 0) {
2494                                         i = groupSeparator.Length; 
2495                                         do {
2496                                                 buffy[--position] = groupSeparator[--i];
2497                                         } while (i > 0);
2498                                         
2499                                         k = (j < groupSizes.Length) ? 
2500                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2501                                 }
2502                         }                
2503
2504                         buffy[--position] = digitLowerTable[value];
2505
2506                         return new string (buffy, position, (size - position));
2507                 }
2508
2509                 private static string FormatNumber (ulong value, int precision, NumberFormatInfo nfi) 
2510                 {
2511                         int i, j, k;
2512                         char[] groupSeparator = nfi.NumberGroupSeparator.ToCharArray ();
2513                         char[] decimalSeparator = nfi.NumberDecimalSeparator.ToCharArray ();
2514                         int[] groupSizes = nfi.NumberGroupSizes;
2515
2516                         int padding = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
2517                         int size = maxLongLength + (maxLongLength * groupSeparator.Length) + padding +
2518                         decimalSeparator.Length + 2;
2519                         char[] buffy = new char[size];
2520                         int position = size;
2521                         
2522                         // right pad it w/ precision 0's
2523                         while (padding-- > 0)
2524                                 buffy[--position] = '0';
2525                         
2526                         // put on decimal separator
2527                         if (position != size) {
2528                                 i = decimalSeparator.Length; 
2529                                 do {
2530                                         buffy[--position] = decimalSeparator[--i];
2531                                 } while (i > 0);                        
2532                         }
2533
2534                         // loop through, keeping track of where you are in the
2535                         // group sizes array and putting out the group separator
2536                         // when needed
2537                         j = 0;
2538                         k = groupSizes[j++];
2539
2540                         while (value >= 10) {
2541                                 buffy[--position] = digitLowerTable[(value % 10)];
2542                                 value /= 10;
2543
2544                                 if (--k == 0) {
2545                                         i = groupSeparator.Length; 
2546                                         do {
2547                                                 buffy[--position] = groupSeparator[--i];
2548                                         } while (i > 0);
2549                                         
2550                                         k = (j < groupSizes.Length) ? 
2551                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2552                                 }
2553                         }                
2554
2555                         buffy[--position] = digitLowerTable[value];
2556
2557                         return new string (buffy, position, (size - position));
2558                 }               
2559
2560                 // ============ Percent Formatting ============ //
2561
2562                 //
2563                 //  Percent Format: Used for strings containing a percentage. The
2564                 //  PercentSymbol, PercentGroupSizes, PercentGroupSeparator, and
2565                 //  PercentDecimalSeparator members of a NumberFormatInfo supply
2566                 //  the Percent symbol, size and separator for digit groupings, and
2567                 //  decimal separator, respectively.
2568                 //  PercentNegativePattern and PercentPositivePattern determine the
2569                 //  symbols used to represent negative and positive values. For example,
2570                 //  a negative value may be prefixed with a minus sign, or enclosed in
2571                 //  parentheses.
2572                 //  If no precision is specified, the number of decimal places in the result
2573                 //  is set by NumberFormatInfo.PercentDecimalDigits. Results are
2574                 //  rounded to the nearest representable value when necessary.
2575                 //  The result is scaled by 100 (.99 becomes 99%).
2576                 //
2577                 //  The pattern of the number determines how the output looks, where
2578                 //  the percent sign goes, where the negative sign goes, etc.
2579                 //  IFormattable documentation lists the patterns and their values,
2580                 //  I have them commented out in the switch statement
2581                 //
2582
2583                 private static string FormatPercent (byte value, int precision, NumberFormatInfo nfi) 
2584                 {
2585                         return FormatPercent ((uint)value, precision, nfi);
2586                 }
2587
2588                 private static string FormatPercent (short value, int precision, NumberFormatInfo nfi) 
2589                 {
2590                         return FormatPercent ((int)value, precision, nfi);
2591                 }
2592
2593                 private static string FormatPercent (int value, int precision, NumberFormatInfo nfi) 
2594                 {
2595                         int i, j, k;
2596                         bool negative = (value < 0);
2597
2598                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
2599                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
2600                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
2601                         int[] groupSizes = nfi.PercentGroupSizes;
2602                         int pattern = negative ? nfi.PercentNegativePattern : nfi.PercentPositivePattern;
2603                         int symbolLength = percentSymbol.Length;
2604                         
2605                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
2606                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
2607                         decimalSeparator.Length + symbolLength; 
2608                         char[] buffy = new char[size];
2609                         int position = size;
2610
2611                         // set up the pattern from IFormattible
2612                         if (negative) {
2613                                 i = symbolLength; 
2614  
2615                                 switch (pattern) {
2616                                 case 0: // -nnn %
2617                                         do {
2618                                                 buffy[--position] = percentSymbol[--i];
2619                                         } while (i > 0);
2620                                         buffy[--position] = ' '; 
2621                                         break;
2622                                 case 1: // -nnn%
2623                                         do {
2624                                                 buffy[--position] = percentSymbol[--i];
2625                                         } while (i > 0);
2626                                         break;
2627                                 // case 2: // -%nnn
2628                                 //      break;
2629                                 }
2630                         } else {
2631                                 i = symbolLength; 
2632                                 switch (pattern) {
2633                                 case 0: // nnn %
2634                                         do {
2635                                                 buffy[--position] = percentSymbol[--i];
2636                                         } while (i > 0);
2637                                         buffy[--position] = ' ';                                        
2638                                         break;
2639                                 case 1: // nnn%
2640                                         do {
2641                                                 buffy[--position] = percentSymbol[--i];
2642                                         } while (i > 0);
2643                                         break;
2644                                 // case 2: // %nnn
2645                                 //      break;
2646                                 }
2647                         }
2648                         
2649                         // right pad it w/ precision 0's
2650                         while (padding-- > 0)
2651                                 buffy[--position] = '0';
2652
2653                         // put on decimal separator if we moved over and put a 0 
2654                         if (position < size && buffy[position] == '0') {
2655                                 i = decimalSeparator.Length; 
2656                                 do {
2657                                         buffy[--position] = decimalSeparator[--i];
2658                                 } while (i > 0);                        
2659                         }
2660
2661                         // loop through, keeping track of where you are in the
2662                         // group sizes array and putting out the group separator
2663                         // when needed
2664                         j = 0;
2665                         k = groupSizes[j++];
2666
2667                         // all values are multiplied by 100, so tack on two 0's
2668                         if (value != 0) 
2669                                 for (int c = 0; c < 2; c++) {
2670                                         buffy[--position] = '0';
2671                                         
2672                                         if (--k == 0) {
2673                                                 i = groupSeparator.Length; 
2674                                                 do {
2675                                                         buffy[--position] = groupSeparator[--i];
2676                                                 } while (i > 0);
2677                                                 
2678                                                 k = (j < groupSizes.Length) ? 
2679                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2680                                         }
2681                                 }
2682
2683                         // negative hack for numbers past MinValue
2684                         if (negative)
2685                                 if (value <= -10) {
2686                                         buffy[--position] = digitLowerTable[-(value % 10)];
2687                                         value = value / -10;
2688                                         
2689                                         if (--k == 0) {
2690                                                 i = groupSeparator.Length; 
2691                                                 do {
2692                                                         buffy[--position] = groupSeparator[--i];
2693                                                 } while (i > 0);
2694                                                 
2695                                                 k = (j < groupSizes.Length) ? 
2696                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2697                                         }
2698                                 } else value = -value;
2699
2700                         while (value >= 10) {
2701                                 buffy[--position] = digitLowerTable[(value % 10)];
2702                                 value /= 10;
2703
2704                                 if (--k == 0) {
2705                                         i = groupSeparator.Length; 
2706                                         do {
2707                                                 buffy[--position] = groupSeparator[--i];
2708                                         } while (i > 0);
2709                                         
2710                                         k = (j < groupSizes.Length) ? 
2711                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2712                                 }
2713                         }                
2714
2715                         buffy[--position] = digitLowerTable[value];
2716
2717                         // end the pattern on the left hand side
2718                         if (negative) {
2719                                 i = symbolLength; 
2720  
2721                                 switch (pattern) {
2722                                 case 0: // -nnn %
2723                                         buffy[--position] = '-'; 
2724                                         break;
2725                                 case 1: // -nnn%
2726                                         buffy[--position] = '-'; 
2727                                         break;
2728                                 case 2: // -%nnn
2729                                         do {
2730                                                 buffy[--position] = percentSymbol[--i];
2731                                         } while (i > 0);
2732                                         buffy[--position] = '-'; 
2733                                         break;
2734                                 }
2735                         } else {
2736                                 i = symbolLength; 
2737                                 switch (pattern) {
2738                                 // case 0: // nnn %
2739                                 //      break;
2740                                 // case 1: // nnn%
2741                                 //      break;
2742                                 case 2: // %nnn
2743                                         do {
2744                                                 buffy[--position] = percentSymbol[--i];
2745                                         } while (i > 0);
2746                                         break;
2747                                 }
2748                         }
2749                         
2750                         return new string (buffy, position, (size - position));
2751                 }
2752
2753                 private static string FormatPercent (long value, int precision, NumberFormatInfo nfi) 
2754                 {
2755                         int i, j, k;
2756                         bool negative = (value < 0);
2757
2758                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
2759                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
2760                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
2761                         int[] groupSizes = nfi.PercentGroupSizes;
2762                         int pattern = negative ? nfi.PercentNegativePattern : nfi.PercentPositivePattern;
2763                         int symbolLength = percentSymbol.Length;
2764                         
2765                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
2766                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
2767                         decimalSeparator.Length + symbolLength; 
2768                         char[] buffy = new char[size];
2769                         int position = size;
2770
2771                         // set up the pattern from IFormattible
2772                         if (negative) {
2773                                 i = symbolLength; 
2774  
2775                                 switch (pattern) {
2776                                 case 0: // -nnn %
2777                                         do {
2778                                                 buffy[--position] = percentSymbol[--i];
2779                                         } while (i > 0);
2780                                         buffy[--position] = ' '; 
2781                                         break;
2782                                 case 1: // -nnn%
2783                                         do {
2784                                                 buffy[--position] = percentSymbol[--i];
2785                                         } while (i > 0);
2786                                         break;
2787                                 // case 2: // -%nnn
2788                                 //      break;
2789                                 }
2790                         } else {
2791                                 i = symbolLength; 
2792                                 switch (pattern) {
2793                                 case 0: // nnn %
2794                                         do {
2795                                                 buffy[--position] = percentSymbol[--i];
2796                                         } while (i > 0);
2797                                         buffy[--position] = ' ';                                        
2798                                         break;
2799                                 case 1: // nnn%
2800                                         do {
2801                                                 buffy[--position] = percentSymbol[--i];
2802                                         } while (i > 0);
2803                                         break;
2804                                 // case 2: // %nnn
2805                                 //      break;
2806                                 }
2807                         }
2808                         
2809                         // right pad it w/ precision 0's
2810                         while (padding-- > 0)
2811                                 buffy[--position] = '0';
2812
2813                         // put on decimal separator if we moved over and put a 0 
2814                         if (position < size && buffy[position] == '0') {
2815                                 i = decimalSeparator.Length; 
2816                                 do {
2817                                         buffy[--position] = decimalSeparator[--i];
2818                                 } while (i > 0);                        
2819                         }
2820
2821                         // loop through, keeping track of where you are in the
2822                         // group sizes array and putting out the group separator
2823                         // when needed
2824                         j = 0;
2825                         k = groupSizes[j++];
2826
2827                         // all values are multiplied by 100, so tack on two 0's
2828                         if (value != 0) 
2829                                 for (int c = 0; c < 2; c++) {
2830                                         buffy[--position] = '0';
2831                                         
2832                                         if (--k == 0) {
2833                                                 i = groupSeparator.Length; 
2834                                                 do {
2835                                                         buffy[--position] = groupSeparator[--i];
2836                                                 } while (i > 0);
2837                                                 
2838                                                 k = (j < groupSizes.Length) ? 
2839                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2840                                         }
2841                                 }
2842
2843                         // negative hack for numbers past MinValue
2844                         if (negative)
2845                                 if (value <= -10) {
2846                                         buffy[--position] = digitLowerTable[-(value % 10)];
2847                                         value = value / -10;
2848                                         
2849                                         if (--k == 0) {
2850                                                 i = groupSeparator.Length; 
2851                                                 do {
2852                                                         buffy[--position] = groupSeparator[--i];
2853                                                 } while (i > 0);
2854                                                 
2855                                                 k = (j < groupSizes.Length) ? 
2856                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2857                                         }
2858                                 } else value = -value;
2859
2860                         while (value >= 10) {
2861                                 buffy[--position] = digitLowerTable[(value % 10)];
2862                                 value /= 10;
2863
2864                                 if (--k == 0) {
2865                                         i = groupSeparator.Length; 
2866                                         do {
2867                                                 buffy[--position] = groupSeparator[--i];
2868                                         } while (i > 0);
2869                                         
2870                                         k = (j < groupSizes.Length) ? 
2871                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2872                                 }
2873                         }                
2874
2875                         buffy[--position] = digitLowerTable[value];
2876
2877                         // end the pattern on the left hand side
2878                         if (negative) {
2879                                 i = symbolLength; 
2880  
2881                                 switch (pattern) {
2882                                 case 0: // -nnn %
2883                                         buffy[--position] = '-'; 
2884                                         break;
2885                                 case 1: // -nnn%
2886                                         buffy[--position] = '-'; 
2887                                         break;
2888                                 case 2: // -%nnn
2889                                         do {
2890                                                 buffy[--position] = percentSymbol[--i];
2891                                         } while (i > 0);
2892                                         buffy[--position] = '-'; 
2893                                         break;
2894                                 }
2895                         } else {
2896                                 i = symbolLength; 
2897                                 switch (pattern) {
2898                                 // case 0: // nnn %
2899                                 //      break;
2900                                 // case 1: // nnn%
2901                                 //      break;
2902                                 case 2: // %nnn
2903                                         do {
2904                                                 buffy[--position] = percentSymbol[--i];
2905                                         } while (i > 0);
2906                                         break;
2907                                 }
2908                         }
2909                         
2910                         return new string (buffy, position, (size - position));
2911                 }
2912
2913                 private static string FormatPercent (sbyte value, int precision, NumberFormatInfo nfi) 
2914                 {
2915                         return FormatPercent ((int)value, precision, nfi);
2916                 }
2917
2918                 private static string FormatPercent (ushort value, int precision, NumberFormatInfo nfi) 
2919                 {
2920                         return FormatPercent ((uint)value, precision, nfi);
2921                 }
2922
2923                 private static string FormatPercent (uint value, int precision, NumberFormatInfo nfi) 
2924                 {
2925                         int i, j, k;
2926
2927                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
2928                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
2929                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
2930                         int[] groupSizes = nfi.PercentGroupSizes;
2931                         int pattern = nfi.PercentPositivePattern;
2932                         int symbolLength = percentSymbol.Length;
2933                         
2934                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
2935                         int size = maxIntLength + (groupSeparator.Length * maxIntLength) + padding + 2 + 
2936                         decimalSeparator.Length + symbolLength; 
2937                         char[] buffy = new char[size];
2938                         int position = size;
2939
2940                         // set up the pattern from IFormattible
2941                         i = symbolLength;                       
2942                         switch (pattern) {
2943                         case 0: // -nnn %
2944                                 do {
2945                                         buffy[--position] = percentSymbol[--i];
2946                                 } while (i > 0);
2947                                 buffy[--position] = ' '; 
2948                                 break;
2949                         case 1: // -nnn%
2950                                 do {
2951                                         buffy[--position] = percentSymbol[--i];
2952                                 } while (i > 0);
2953                                 break;
2954                         // case 2: // -%nnn
2955                         //      break;
2956                         }
2957
2958                         // right pad it w/ precision 0's
2959                         while (padding-- > 0)
2960                                 buffy[--position] = '0';
2961
2962                         // put on decimal separator if we moved over and put a 0 
2963                         if (position < size && buffy[position] == '0') {
2964                                 i = decimalSeparator.Length; 
2965                                 do {
2966                                         buffy[--position] = decimalSeparator[--i];
2967                                 } while (i > 0);                        
2968                         }
2969
2970                         // loop through, keeping track of where you are in the
2971                         // group sizes array and putting out the group separator
2972                         // when needed
2973                         j = 0;
2974                         k = groupSizes[j++];
2975
2976                         if (value != 0) 
2977                                 for (int c = 0; c < 2; c++) {
2978                                         buffy[--position] = '0';
2979                                         
2980                                         if (--k == 0) {
2981                                                 i = groupSeparator.Length; 
2982                                                 do {
2983                                                         buffy[--position] = groupSeparator[--i];
2984                                                 } while (i > 0);
2985                                                 
2986                                                 k = (j < groupSizes.Length) ? 
2987                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
2988                                         }
2989                                 }
2990
2991                         while (value >= 10) {
2992                                 buffy[--position] = digitLowerTable[(value % 10)];
2993                                 value /= 10;
2994
2995                                 if (--k == 0) {
2996                                         i = groupSeparator.Length; 
2997                                         do {
2998                                                 buffy[--position] = groupSeparator[--i];
2999                                         } while (i > 0);
3000                                         
3001                                         k = (j < groupSizes.Length) ? 
3002                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3003                                 }
3004                         }                
3005
3006                         buffy[--position] = digitLowerTable[value];
3007
3008                         i = symbolLength; 
3009                         switch (pattern) {
3010                         // case 0: // nnn %
3011                         //      break;
3012                         // case 1: // nnn%
3013                         //      break;
3014                         case 2: // %nnn
3015                                 do {
3016                                         buffy[--position] = percentSymbol[--i];
3017                                 } while (i > 0);
3018                                 break;
3019                         }
3020                         
3021                         return new string (buffy, position, (size - position));
3022                 }
3023
3024                 private static string FormatPercent (ulong value, int precision, NumberFormatInfo nfi) 
3025                 {
3026                         int i, j, k;
3027
3028                         char[] groupSeparator = nfi.PercentGroupSeparator.ToCharArray ();
3029                         char[] decimalSeparator = nfi.PercentDecimalSeparator.ToCharArray ();
3030                         char[] percentSymbol = nfi.PercentSymbol.ToCharArray ();
3031                         int[] groupSizes = nfi.PercentGroupSizes;
3032                         int pattern = nfi.PercentPositivePattern;
3033                         int symbolLength = percentSymbol.Length;
3034                         
3035                         int padding = (precision >= 0) ? precision : nfi.PercentDecimalDigits;       
3036                         int size = maxLongLength + (groupSeparator.Length * maxLongLength) + padding + 2 + 
3037                         decimalSeparator.Length + symbolLength; 
3038                         char[] buffy = new char[size];
3039                         int position = size;
3040
3041                         // set up the pattern from IFormattible
3042                         i = symbolLength;                       
3043                         switch (pattern) {
3044                         case 0: // -nnn %
3045                                 do {
3046                                         buffy[--position] = percentSymbol[--i];
3047                                 } while (i > 0);
3048                                 buffy[--position] = ' '; 
3049                                 break;
3050                         case 1: // -nnn%
3051                                 do {
3052                                         buffy[--position] = percentSymbol[--i];
3053                                 } while (i > 0);
3054                                 break;
3055                         // case 2: // -%nnn
3056                         //      break;
3057                         }
3058
3059                         // right pad it w/ precision 0's
3060                         while (padding-- > 0)
3061                                 buffy[--position] = '0';
3062
3063                         // put on decimal separator if we moved over and put a 0 
3064                         if (position < size && buffy[position] == '0') {
3065                                 i = decimalSeparator.Length; 
3066                                 do {
3067                                         buffy[--position] = decimalSeparator[--i];
3068                                 } while (i > 0);                        
3069                         }
3070
3071                         // loop through, keeping track of where you are in the
3072                         // group sizes array and putting out the group separator
3073                         // when needed
3074                         j = 0;
3075                         k = groupSizes[j++];
3076
3077                         if (value != 0) 
3078                                 for (int c = 0; c < 2; c++) {
3079                                         buffy[--position] = '0';
3080                                         
3081                                         if (--k == 0) {
3082                                                 i = groupSeparator.Length; 
3083                                                 do {
3084                                                         buffy[--position] = groupSeparator[--i];
3085                                                 } while (i > 0);
3086                                                 
3087                                                 k = (j < groupSizes.Length) ? 
3088                                                 groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3089                                         }
3090                                 }
3091                         
3092                         while (value >= 10) {
3093                                 buffy[--position] = digitLowerTable[(value % 10)];
3094                                 value /= 10;
3095
3096                                 if (--k == 0) {
3097                                         i = groupSeparator.Length; 
3098                                         do {
3099                                                 buffy[--position] = groupSeparator[--i];
3100                                         } while (i > 0);
3101                                         
3102                                         k = (j < groupSizes.Length) ? 
3103                                         groupSizes[j++] : groupSizes[(groupSizes.Length - 1)];
3104                                 }
3105                         }                
3106
3107                         buffy[--position] = digitLowerTable[value];
3108
3109                         i = symbolLength; 
3110                         switch (pattern) {
3111                         // case 0: // nnn %
3112                         //      break;
3113                         // case 1: // nnn%
3114                         //      break;
3115                         case 2: // %nnn
3116                                 do {
3117                                         buffy[--position] = percentSymbol[--i];
3118                                 } while (i > 0);
3119                                 break;
3120                         }
3121                         
3122                         return new string (buffy, position, (size - position));
3123                 }
3124
3125                 // ============ Format Hexadecimal ============ //
3126
3127                 // 
3128                 // For strings in base 16. Only valid w/ integers. Precision 
3129                 // specifies number of digits in the string, if it specifies
3130                 // more digits than we need, left pad w/ 0's. The case of the
3131                 // the format specifier 'X' or 'x' determines lowercase or
3132                 // capital digits in the output.
3133                 //
3134                 // Whew. Straight forward Hex formatting, however only
3135                 // go 8 places max when dealing with an int (not counting
3136                 // precision padding) and 16 when dealing with a long. This
3137                 // is to cut off the loop when dealing with negative values,
3138                 // which will loop forever when you hit -1;
3139                 //
3140
3141                 private static string FormatHexadecimal (byte value, int precision, bool upper)
3142                 {                    
3143                         if (precision < 0) precision = 0;
3144                         int size = maxByteLength + precision;
3145                         char[] buffy = new char[size];
3146                         char[] table = upper ? digitUpperTable : digitLowerTable;
3147                         int position = size;
3148                         ushort mask = (1 << 4) - 1;
3149
3150                         // loop through right to left, shifting and looking up
3151                         // our value. Don't worry about negative
3152                         do {
3153                                 buffy[--position] = table[(value & mask)];
3154                                 value = (byte)(value >> 4);
3155                         } while (value != 0);
3156
3157                         // pad w/ 0's if they want more length, if not, ignore
3158                         precision -= (size - position);                         
3159                         while (precision > 0 && position > 1) {
3160                                 buffy[--position] = '0';
3161                                 precision--;
3162                         }
3163                         
3164                         return new string(buffy, position, (size - position));
3165                 }
3166
3167                 private static string FormatHexadecimal (short value, int precision, bool upper)
3168                 {
3169                         if (precision < 0) precision = 0;
3170                         int size = maxShortLength + precision;
3171                         char[] buffy = new char[size];
3172                         char[] table = upper ? digitUpperTable : digitLowerTable;
3173                         int position = size;
3174                         short mask = (1 << 4) - 1;
3175
3176                         // loop through right to left, shifting and looking up
3177                         // our value. If value is negavite stop after 4 F's
3178                         do {
3179                                 buffy[--position] = table[(value & mask)];
3180                                 value = (short)(value >> 4);
3181                         } while (value != 0 && position > (size - 4));
3182
3183                         // pad w/ 0's if they want more length, if not, ignore
3184                         precision -= (size - position);                         
3185                         while (precision > 0 && position > 1) {
3186                                 buffy[--position] = '0';
3187                                 precision--;
3188                         }
3189                         
3190                         return new string(buffy, position, (size - position));
3191                 }
3192
3193                 private static string FormatHexadecimal (int value, int precision, bool upper)
3194                 {
3195                         if (precision < 0) precision = 0;
3196                         int size = maxIntLength + precision;
3197                         char[] buffy = new char[size];
3198                         char[] table = upper ? digitUpperTable : digitLowerTable;
3199                         int position = size;
3200                         int mask = (1 << 4) - 1;
3201
3202                         // loop through right to left, shifting and looking up
3203                         // our value. If value is negavite stop after 8 F's
3204                         do {
3205                                 buffy[--position] = table[(value & mask)];
3206                                 value = value >> 4;
3207                         } while (value != 0 && position > (size - 8));
3208
3209                         // pad w/ 0's if they want more length, if not, ignore
3210                         precision -= (size - position);                         
3211                         while (precision > 0 && position > 1) {
3212                                 buffy[--position] = '0';
3213                                 precision--;
3214                         }
3215                         
3216                         return new string(buffy, position, (size - position));
3217                 }
3218
3219                 private static string FormatHexadecimal (long value, int precision, bool upper)
3220                 {
3221                         if (precision < 0) precision = 0;
3222                         int size = maxLongLength + precision;
3223                         char[] buffy = new char[size];
3224                         char[] table = upper ? digitUpperTable : digitLowerTable;
3225                         int position = size;
3226                         long mask = (1 << 4) - 1;
3227                         
3228                         // loop through right to left, shifting and looking up
3229                         // our value. If value is negavite stop after 16 F's
3230                         do {
3231                                 buffy[--position] = table[(value & mask)];
3232                                 value = value >> 4;
3233                         } while (value != 0 && position > (size - 16));
3234
3235                         // pad w/ 0's if they want more length, if not, ignore
3236                         precision -= (size - position);                         
3237                         while (precision > 0 && position > 1) {
3238                                 buffy[--position] = '0';
3239                                 precision--;
3240                         }
3241                         
3242                         return new string(buffy, position, (size - position));
3243                 }
3244
3245                 private static string FormatHexadecimal (sbyte value, int precision, bool upper)
3246                 {
3247                         if (precision < 0) precision = 0;
3248                         int size = maxByteLength + precision;
3249                         char[] buffy = new char[size];
3250                         char[] table = upper ? digitUpperTable : digitLowerTable;
3251                         int position = size;
3252                         short mask = (1 << 4) - 1;
3253
3254                         // loop through right to left, shifting and looking up
3255                         // our value. If value is negavite stop after 2 F's
3256                         do {
3257                                 buffy[--position] = table[(value & mask)];
3258                                 value = (sbyte)(value >> 4);
3259                         } while (value != 0 && position > (size - 2));
3260
3261                         // pad w/ 0's if they want more length, if not, ignore
3262                         precision -= (size - position);                         
3263                         while (precision > 0 && position > 1) {
3264                                 buffy[--position] = '0';
3265                                 precision--;
3266                         }
3267                         
3268                         return new string(buffy, position, (size - position));
3269                 }
3270
3271                 private static string FormatHexadecimal (ushort value, int precision, bool upper)
3272                 {                       
3273                         if (precision < 0) precision = 0;
3274                         int size = maxShortLength + precision;
3275                         char[] buffy = new char[size];
3276                         char[] table = upper ? digitUpperTable : digitLowerTable;
3277                         int position = size;
3278                         int mask = (1 << 4) - 1;
3279
3280                         // loop through right to left, shifting and looking up
3281                         // our value. Don't worry about negative
3282                         do {
3283                                 buffy[--position] = table[(value & mask)];
3284                                 value = (ushort)(value >> 4);
3285                         } while (value != 0);
3286
3287                         // pad w/ 0's if they want more length, if not, ignore
3288                         precision -= (size - position);                         
3289                         while (precision > 0 && position > 1) {
3290                                 buffy[--position] = '0';
3291                                 precision--;
3292                         }
3293                         
3294                         return new string(buffy, position, (size - position));
3295                 }
3296
3297                 private static string FormatHexadecimal (uint value, int precision, bool upper)
3298                 {                       
3299                         if (precision < 0) precision = 0;
3300                         int size = maxIntLength + precision;
3301                         char[] buffy = new char[size];
3302                         char[] table = upper ? digitUpperTable : digitLowerTable;
3303                         int position = size;
3304                         uint mask = (1 << 4) - 1;
3305
3306                         // loop through right to left, shifting and looking up
3307                         // our value. Don't worry about negative
3308                         do {
3309                                 buffy[--position] = table[(value & mask)];
3310                                 value = value >> 4;
3311                         } while (value != 0);
3312
3313                         // pad w/ 0's if they want more length, if not, ignore
3314                         precision -= (size - position);                         
3315                         while (precision > 0 && position > 1) {
3316                                 buffy[--position] = '0';
3317                                 precision--;
3318                         }
3319                         
3320                         return new string(buffy, position, (size - position));
3321                 }
3322
3323                 private static string FormatHexadecimal (ulong value, int precision, bool upper)
3324                 {                       
3325                         if (precision < 0) precision = 0;
3326                         int size = maxLongLength + precision;
3327                         char[] buffy = new char[size];
3328                         char[] table = upper ? digitUpperTable : digitLowerTable;
3329                         int position = size;
3330                         ulong mask = (1 << 4) - 1;
3331                         
3332                         // loop through right to left, shifting and looking up
3333                         // our value. Don't worry about negative
3334                         do {
3335                                 buffy[--position] = table[value & mask];
3336                                 value = value >> 4;
3337                         } while (value != 0);
3338                         
3339                         // pad w/ 0's if they want more length, if not, ignore
3340                         precision -= (size - position);
3341                         while (precision > 0 && position > 1) {
3342                                 buffy[--position] = '0';
3343                                 precision--;
3344                         }
3345
3346                         return new string(buffy, position, (size - position));
3347                 }
3348
3349         }
3350 }